例子
# Rules for how to combine various fields based on there names
combine(::Val{:foo}, foo1, foo2) = foo1+foo2
combine(::Val{:bar}, bar1, bar2) = bar2 - bar1
combine(::Val{:boop}, boop1, boop2) = min(boop1, boop2)
# combining 2 things of the same type
function combine(aa::T, bb::T) where T
T(combine.(
[Val{fn}() for fn in fieldnames(T)],
getfield.(Ref(aa), 1:nfields(T)),
getfield.(Ref(bb), 1:nfields(T))
)...)
end
我认为总的模式是有用的
T
有用吗。
我的问题是,这将完全决定于
专门化(在编译时),
哪一级
combine
正在调用方法?
演示
julia> struct Flooper
foo::Int
bar::Int
end
julia> combine(Flooper(10,1), Flooper(3, 9))
Flooper(13, 8)
我正在努力阅读
@code_warntype
.
julia> @code_warntype combine(Flooper(10,1), Flooper(3, 9))
Body::Any
5 1 ââ %1 = Base.Broadcast.materialize::typeof(Base.Broadcast.materialize) â
â %2 = new(Main.:(##5#6))::getfield(Main, Symbol("##5#6")) â
â %3 = new(getfield(Base, Symbol("##9#10")){DataType}, :($(Expr(:static_parameter, 1))))::getfield(Base, Symbol("##9#10")){DataType}
ââââ goto 2 if not false âââ» fieldcount
2 ââ %5 = Ï (false, Bool) âââ
ââââ goto 4 if not %5 âââ
3 ââ nothing â
4 ââ goto 6 if not false âââ
5 ââ nothing â
6 ââ %10 = Base.not_int(true)::Bool ââââ» !
ââââ goto 8 if not %10 âââ
7 ââ nothing â
8 ââ %13 = Ï (:($(Expr(:static_parameter, 1))), Type{Flooper}) âââ
â Base.getfield(%13, :(:name)) ââââ» getproperty
â Base.getfield(NamedTuple{names,T<:Tuple}, :(:name)) ââââ
ââââ goto 10 if not false âââ
9 ââ nothing â
10 â %18 = Ï (:($(Expr(:static_parameter, 1))), Type{Flooper}) âââ
â %19 = Base.getfield(%18, :(:abstract))::Bool ââââ» getproperty
ââââ goto 12 if not %19 âââ
11 â goto 14 âââ
12 â %22 = Ï (:($(Expr(:static_parameter, 1))), Type{Flooper}) âââ
â Base.getfield(%22, :(:name)) ââââ» getproperty
â %24 = Base.Tuple::Type{Tuple} âââ
â Base.getfield(%24, :(:name)) ââââ» getproperty
ââââ goto 13 if not false âââ
13 â %27 = Ï (false, Bool) âââ
14 â %28 = Ï (11 => %19, 13 => %27)::Bool ââ
ââââ goto 17 if not %28 âââ» fieldcount
15 â %30 = new(Core.ErrorException, "type does not have a definite number of fields")::ErrorException ââââ»â· error
â Base.throw(%30) ââââ
ââââ unreachable ââââ
16 â unreachable âââ
17 â %34 = Ï (:($(Expr(:static_parameter, 1))), Type{Flooper}) âââ
â %35 = Base.getfield(%34, :(:types))::Core.SimpleVector ââââ» getproperty
â %36 = $(Expr(:gc_preserve_begin, Core.SSAValue(35))) ââââ» length
â %37 = $(Expr(:foreigncall, :(:jl_value_ptr), Ptr{Nothing}, svec(Any), :(:ccall), 1, Core.SSAValue(35)))::Ptr{Nothing}om_objref
â %38 = Base.bitcast(Ptr{Int64}, %37)::Ptr{Int64} âââââ» convert
â %39 = Base.pointerref(%38, 1, 1)::Int64 ââââââ» unsafe_load
â $(Expr(:gc_preserve_end, Core.SSAValue(36))) ââââ» length
ââââ goto 18 âââ
18 â %42 = invoke Base.ntuple(%3::getfield(Base, Symbol("##9#10")){DataType}, %39::Int64)::Tuple ââ
ââââ goto 19 ââ
19 â %44 = Base.Generator(%2, %42)::Base.Generator{_1,getfield(Main, Symbol("##5#6"))} where _1 â
â %45 = Base.collect(%44)::Any â
â %46 = new(Base.RefValue{Flooper}, %%aa)::Base.RefValue{Flooper} âââ»â· Type
â %47 = Base.ifelse(true, 2, 0)::Int64 âââ»â· Type
â %48 = new(UnitRange{Int64}, 1, %47)::UnitRange{Int64} âââ
â %49 = Core.tuple(%46, %48)::Tuple{Base.RefValue{Flooper},UnitRange{Int64}} ââ» broadcasted
â %50 = new(Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(getfield),Tuple{Base.RefValue{Flooper},UnitRange{Int64}}}, getfield, %49, nothing)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(getfield),Tuple{Base.RefValue{Flooper},UnitRange{Int64}}}
â %51 = new(Base.RefValue{Flooper}, %%bb)::Base.RefValue{Flooper} âââ»â· Type
â %52 = Base.ifelse(true, 2, 0)::Int64 âââ»â· Type
â %53 = new(UnitRange{Int64}, 1, %52)::UnitRange{Int64} âââ
â %54 = Core.tuple(%51, %53)::Tuple{Base.RefValue{Flooper},UnitRange{Int64}} ââ» broadcasted
â %55 = new(Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(getfield),Tuple{Base.RefValue{Flooper},UnitRange{Int64}}}, getfield, %54, nothing)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(getfield),Tuple{Base.RefValue{Flooper},UnitRange{Int64}}}
â %56 = Main.combine::typeof(combine) â
â %57 = Base.Broadcast.broadcastable(%45)::Any ââ» broadcasted
â %58 = Base.Broadcast.combine_styles(%57)::Base.Broadcast.BroadcastStyle âââ» combine_styles
â %59 = isa(%58, Base.Broadcast.DefaultArrayStyle{1})::Bool âââ
ââââ goto 21 if not %59 âââ
20 â goto 22 âââ
21 â %62 = Base.Broadcast.result_style(%58, :($(QuoteNode(Base.Broadcast.DefaultArrayStyle{1}()))))::Anyâ
ââââ goto 22 âââ
22 â %64 = Ï (20 => :($(QuoteNode(Base.Broadcast.DefaultArrayStyle{1}()))), 21 => %62)::Any âââ
ââââ goto 23 âââ
23 â %66 = Base.Broadcast.broadcasted(%64, %56, %57, %50, %55)::Any ââ
ââââ goto 24 ââ
24 â %68 = %1(%66)::Any â
â %69 = Core._apply(:($(Expr(:static_parameter, 1))), %68)::Any â
ââââ return %69
我想另一种选择,如果在专门化过程中调用哪个方法不是完全确定的,
@generated function
.
但我宁愿不要,我不必。
我对朱莉娅0.7的答案很感兴趣,
(尽管0.6对于上下文来说很有趣,因为我怀疑在不同版本之间它有轻微的变化)