首页 > 解决方案 > 实例化子类型之前的 Julia Subtyp 验证

问题描述

只要创建子类型而不是实例化时,我只需要在子类型结构上调用 validation_field() “此函数将验证子结构”。所以首先我如何在超类型中定义子类型(是否有任何基本函数,例如“getSubtype()”),朱莉娅中是否有任何“this”关键字,我的方法有什么替代方法吗?

function validate_field(field::Model1)
    @assert typeof(attr)==float, "Validation error for type of default"
end

struct Model1

  validate_field("this")
end


struct G <: Model1
atrr::float 
end

标签: inheritancejuliathisparent-child

解决方案


验证功能可以通过反射实现:

julia> function validate_field(::Type{T}) where {T<:Model1}
           fieldtype(T, :attr) <: Float64 || error("`attr` has invalid field type")
       end
validate_field (generic function with 2 methods)

julia> validate_field(G)
true

julia> struct H <: Model1
           attr::Symbol
       end

julia> validate_field(H)
ERROR: `attr` has invalid field type
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:33
 [2] validate_field(#unused#::Type{H})
   @ Main ./REPL[10]:2
 [3] top-level scope
   @ REPL[13]:1

其余的不会从 Java 继承。首先,没有具体的继承。你只能有抽象超类型,它不能有字段:

abstract type Model1 end

然后,方法不与类型相关联,而是与函数相关联。构造函数也是如此;所以没有构造函数的继承,也没有this.

您可以通过执行以下操作来大致满足您的要求:

julia> subtypes(Model1)
2-element Vector{Any}:
 G
 H

julia> foreach(validate_field, subtypes(Model1))
ERROR: `attr` has invalid field type
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:33
 [2] validate_field(#unused#::Type{H})
   @ Main ./REPL[10]:2
 [3] foreach(f::typeof(validate_field), itr::Vector{Any})
   @ Base ./abstractarray.jl:2141
 [4] top-level scope
   @ REPL[15]:1

但这只会验证运行时某个特定点存在的一组未指定的子类型。

更朱利安的方法是在子对象的消费者中假装(通过鸭子打字)他们有一个与他们所做的任何事情兼容的类型的字段:Model1attr

somefunction(m::Model1) = m.attr^2

将适用于存在适当方法的任何事物^。如果这不起作用,MethodError无论如何你都会得到一个,这并不比来自validate_field.

可能您应该首先熟悉多重分派,以及 Julia 的面向对象的惯用替代方案,然后尝试以不同的方式设计您的方法。


如果你发疯了,你可以使用一种 trait:

julia> HasAttr(::Type{T}) where {T} = Val{false}()
HasAttr (generic function with 1 method)

julia> HasAttr(::Type{T}) where {T<:Model1} = Val{fieldtype(T, :attr) <: Float64}()
HasAttr (generic function with 2 methods)

julia> @code_warntype HasAttr(G)
Variables
  #self#::Core.Const(HasAttr)
  #unused#::Core.Const(G)

Body::Val{true}
1 ─ %1 = Main.fieldtype($(Expr(:static_parameter, 1)), :attr)::Core.Const(Float64)
│   %2 = (%1 <: Main.Float64)::Core.Const(true)
│   %3 = Core.apply_type(Main.Val, %2)::Core.Const(Val{true})
│   %4 = (%3)()::Core.Const(Val{true}())
└──      return %4

julia> some_other_function(m) = some_other_function(m, HasAttr(typeof(m)))
some_other_function (generic function with 1 method)

julia> some_other_function(m, ::Val{true}) = missing
some_other_function (generic function with 2 methods)

julia> some_other_function(G(1.0))
missing

julia> some_other_function(H(:bla))
ERROR: MethodError: no method matching some_other_function(::H, ::Val{false})
Closest candidates are:
  some_other_function(::Any) at REPL[23]:1
  some_other_function(::Any, ::Val{true}) at REPL[24]:1
Stacktrace:
 [1] some_other_function(m::H)
   @ Main ./REPL[23]:1
 [2] top-level scope
   @ REPL[27]:1

但我可以告诉你,这不是你真正想要的......


推荐阅读