如何获取Julia复合类型的深度副本?
这就是背景。我有多个用自己的字段和构造函数定义的复合类型。让我们在此处显示两个简化组件:如何获取Julia复合类型的深度副本?,julia,Julia,这就是背景。我有多个用自己的字段和构造函数定义的复合类型。让我们在此处显示两个简化组件: type component1 x y end type component2 x y z end 现在我想定义一个新类型,这样它就可以在其中保存一个大小为K的数组,其中包含以前定义的复合类型。因此,它是一个具有两个字段的参数化复合类型:一个是整数K,另一个是传递类型的大小为K的数组 type mixture{T} components::Array{T,
type component1
x
y
end
type component2
x
y
z
end
现在我想定义一个新类型,这样它就可以在其中保存一个大小为K的数组,其中包含以前定义的复合类型。因此,它是一个具有两个字段的参数化复合类型:一个是整数K,另一个是传递类型的大小为K的数组
type mixture{T}
components::Array{T, 1}
K::Int64
function mixture(qq::T, K::Int64)
components = Array{typeof(qq), K}
for k in 1:K
components[k] = qq
end
new(components, K)
end
end
但这不是正确的方法。因为所有的K分量都指向一个对象并操纵混合。分量[K]将影响所有的K分量。在python中,我可以用deepcopy解决这个问题。但是Julia中的deepcopy没有为复合类型定义。如何解决此问题?对您的具体问题的回答: 在Julia中定义新类型时,通常会将
Base
中的一些标准方法扩展到新类型,包括deepcopy
。例如:
type MyType
x::Vector
y::Vector
end
import Base.deepcopy
Base.deepcopy(m::MyType) = MyType(deepcopy(m.x), deepcopy(m.y))
现在,您可以通过MyType
的实例调用deepcopy
,您将得到一个新的真正独立的MyType
副本作为输出
注意,我的import Base.deepcopy
实际上是多余的,因为我在函数定义中引用了Base
,例如Base.deepcopy(m::MyType)
。然而,我做了这两件事是为了向您展示从Base
扩展方法的两种方法
第二个注意事项是,如果您的类型有很多字段,您可以使用deepcopy
对这些字段进行迭代,如下所示:
Base.deepcopy(m::MyType) = MyType([ deepcopy(getfield(m, k)) for k = 1:length(names(m)) ]...)
Base.length(m::Mixture) = length(m.components)
对代码的评论:
首先,Julia的标准做法是将类型名称大写,例如Component1
而不是Component1
。当然,你不必这么做,但是
第二,来自:为复合类型的字段声明特定类型。注意,您可以参数化这些声明,例如
type Component1{T1, T2}
x::T1
y::T2
end
第三,以下是我如何定义您的新类型:
type Mixture{T}
components::Vector{T}
Mixture{T}(c::Vector{T}) = new(c)
end
Mixture{T}(c::Vector{T}) = Mixture{eltype(c)}(c)
Mixture(x, K::Int) = Mixture([ deepcopy(x) for k = 1:K ])
我的代码和你的代码之间有几个重要的区别。我会一次看一个
您的K
字段是多余的(我认为),因为它似乎只是组件的长度。因此,将length
方法扩展到新类型可能更简单,如下所示:
Base.deepcopy(m::MyType) = MyType([ deepcopy(getfield(m, k)) for k = 1:length(names(m)) ]...)
Base.length(m::Mixture) = length(m.components)
现在您可以使用length(m)
,其中m
是mixed
的一个实例,以获取先前存储在K
字段中的内容
类型混合物中的内部构造函数不寻常。标准做法是,内部构造函数获取与类型字段一一对应(按顺序)的参数,然后内部构造函数的其余部分只执行初始化类型时希望执行的任何错误检查。您偏离了这一点,因为qq
不一定是数组。这种行为最好保留给外部构造函数。那么,我对构造函数做了什么
mixed
的内部构造函数除了通过new
将参数传递到字段之外,实际上不做任何事情。这是因为目前没有任何需要执行的错误检查(但我可以在将来轻松添加一些)
如果我想调用这个内部构造函数,我需要编写类似于m=mixed{MyType}(x)
,其中x
是Vector{MyType}
。这有点烦人。因此,我的第一个外部构造函数使用eltype(x)
自动推断{…}
的内容。由于我的第一个外部构造函数,我现在可以使用m=mixed(x)
而不是m=mixed{MyType}(x)
初始化mixed
我的第二个外部构造函数对应于您的内部构造函数。在我看来,您在这里追求的行为是在组件的每个字段中使用相同的组件初始化混合物
,重复K次。因此,我通过对x
的循环理解来实现这一点,只要为x
定义了deepcopy
方法,该方法就可以工作。如果不存在deepcopy
方法,您将得到no method exists
错误。这种编程称为duck类型,在Julia中,使用它通常不会造成性能损失
注意,我的第二个外部构造函数将调用我的第一个外部构造函数K
次,每次,我的第一个外部构造函数将调用我的内部构造函数。在更复杂的场景中,这种嵌套功能将大大减少代码重复
对不起,我知道这有很多要接受的。希望能有所帮助。谢谢您的完整回复。我熟悉多次分派的概念,但不确定是否最好的方法是修改Base.deepcopy。也谢谢你的评论。关于第三条注释,不需要在构造函数中声明类型,尽管我设法使用了您的方法,但我不太理解它@我已经更新了我的答案。如果仍然不清楚,请告诉我,我会再试一次:-)谢谢。现在更清楚了(对于我这个朱莉娅:D的初学者来说)