所以这是设置。我有多个复合类型定义了自己的字段和构造函数。让我们在这里展示两个简化的组件:
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中的深度复制没有为复合类型定义。我该如何解决这个问题?
答案 0 :(得分:13)
回答您的具体问题:
在Julia中定义新类型时,通常会将Base
中的一些标准方法扩展到新类型,包括deepcopy
。例如:
type MyType
x::Vector
y::Vector
end
import Base.deepcopy
Base.deepcopy(m::MyType) = MyType(deepcopy(m.x), deepcopy(m.y))
现在,您可以通过deepcopy
的实例调用MyType
,然后您将获得一个新的,真正独立的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)
的内容。由于我的第一个外部构造函数,我现在可以使用Mixture
而不是m = Mixture(x)
来初始化m = Mixture{MyType}(x)
我的第二个外部构造函数对应于您的内部构造函数。在我看来,您在此处的行为是在Mixture
的每个字段中使用相同的组件初始化components
,重复K
次。所以我通过对x
的循环理解来做到这一点,只要为deepcopy
定义了x
方法,它就会起作用。如果不存在deepcopy
方法,则会出现No Method Exists
错误。这种编程称为duck-typing,在Julia中使用它通常没有性能损失。
注意,我的第二个外部构造函数将调用我的第一个外部构造函数K
次,每次,我的第一个外部构造函数将调用我的内部构造函数。在更复杂的情况下,以这种方式嵌套功能将大大减少代码重复。
对不起,我知道这很重要。希望它有所帮助。