我希望能够为用户定义的类型创建一个调度,它基本上会执行一个就地复制.但是,我想以类型稳定的方式进行,因此我想避免getfield直接使用,而是尝试使用生成的函数.是否有类似的类型
type UserType{T}
x::Vector{T}
y::Vector{T}
z::T
end
Run Code Online (Sandbox Code Playgroud)
生成一些功能
recursivecopy!(A::UserType,B::UserType)
# Do it for x
if typeof(A.x) <: AbstractArray
recursivecopy!(A.x,B.x)
else
A.x = B.x
end
# Now for y
if typeof(A.y) <: AbstractArray
recursivecopy!(A.y,B.y)
else
A.y = B.y
end
# Now for z
if typeof(A.z) <: AbstractArray
recursivecopy!(A.z,B.z)
else
A.z = B.z
end
end
Run Code Online (Sandbox Code Playgroud)
将recursivecopy!在RecursiveArrayTools.jl使得这种处理嵌套(Vector{Vector})类型的不错,但唯一的问题是我不知道的领域,用户将不得不提前,只是在编译时该功能将被调用.听起来像生成函数的工作,但我不太确定如何生成它.
你不需要向后弯曲以避免getfield和setfield.朱莉娅可以推断他们就好了.当Julia无法弄清楚它正在访问哪个字段时就会遇到麻烦...就像在for循环中一样.
因此,生成的函数需要做的唯一特殊事情是有效地展开循环,并将常量值拼接到getfield:
julia> immutable A
x::Int
y::Float64
end
julia> @generated function f(x)
args = [:(getfield(x, $i)) for i=1:nfields(x)]
:(tuple($(args...)))
end
f (generic function with 1 method)
julia> f(A(1,2.4))
(1,2.4)
julia> @code_warntype f(A(1,2.4))
Variables:
#self#::#f
x::A
Body:
begin # line 2:
return (Main.tuple)((Main.getfield)(x::A,1)::Int64,(Main.getfield)(x::A,2)::Float64)::Tuple{Int64,Float64}
end::Tuple{Int64,Float64}
Run Code Online (Sandbox Code Playgroud)
就像你可以将多个参数拼接到函数调用一样,你也可以直接将多个表达式拼接到函数体中.
julia> type B
x::Int
y::Float64
end
julia> @generated function f!{T}(dest::T, src::T)
assignments = [:(setfield!(dest, $i, getfield(src, $i))) for i=1:nfields(T)]
:($(assignments...); dest)
end
f! (generic function with 1 method)
julia> f!(B(0,0), B(1, 2.4))
B(1,2.4)
julia> @code_warntype f!(B(0,0), B(1, 2.4))
Variables:
#self#::#f!
dest::B
src::B
Body:
begin # line 2:
(Main.setfield!)(dest::B,1,(Main.getfield)(src::B,1)::Int64)::Int64
(Main.setfield!)(dest::B,2,(Main.getfield)(src::B,2)::Float64)::Float64
return dest::B
end::B
Run Code Online (Sandbox Code Playgroud)
当然,你可以使你理解的主体像你想的那样复杂.这有效地成为你for循环的内部.将数组溅入函数体中会为您展开.