对您的具体问题的回答:
当您在 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)) ]...)
对您的代码的评论:
首先,Julia 的标准做法是大写类型名称,例如Component1 而不是 component1。当然,您不必这样做,但是...
第二,来自Julia docs performance tips:为复合类型的字段声明特定类型。请注意,您可以参数化这些声明,例如
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 字段是多余的(我认为),因为它似乎只是components 的长度。因此,将length 方法扩展到您的新类型可能会更简单,如下所示:
Base.length(m::Mixture) = length(m.components)
现在您可以使用length(m),其中m 是Mixture 的一个实例,以获取之前存储在K 字段中的内容。
您的类型mixture 中的内部构造函数异常。标准做法是内部构造函数采用与您类型的字段一对一(按顺序)对应的参数,然后内部构造函数的其余部分只执行您希望在初始化时执行的任何错误检查类型。您偏离了这一点,因为 qq 不是(必然)一个数组。这种行为更好地保留给外部构造函数。那么,我对构造函数做了什么?
Mixture 的内部构造函数除了通过new 将参数传递到字段中之外并没有真正做任何事情。这是因为目前我不需要执行任何错误检查(但我将来可以轻松添加一些)。
如果我想调用这个内部构造函数,我需要写类似m = Mixture{MyType}(x),其中x 是Vector{MyType}。这有点烦人。所以我的第一个外部构造函数使用eltype(x) 自动推断{...} 的内容。由于我的第一个外部构造函数,我现在可以使用m = Mixture(x) 而不是m = Mixture{MyType}(x) 来初始化Mixture
我的第二个外部构造函数对应于你的内部构造函数。在我看来,您在这里的行为是在components 的每个字段中使用相同的组件初始化Mixture,重复K 次。所以我通过对x 的循环理解来做到这一点,只要为x 定义了deepcopy 方法,它就可以工作。如果不存在deepcopy 方法,您将收到No Method Exists 错误。这种编程称为鸭式编程,在 Julia 中使用它通常不会降低性能。
注意,我的第二个外部构造函数将调用我的第一个外部构造函数K 次,并且每次,我的第一个外部构造函数都会调用我的内部构造函数。在更复杂的场景中,以这种方式嵌套功能将大大减少代码重复。
抱歉,我知道这有很多需要注意的地方。希望对您有所帮助。