如何获取Julia复合类型的深层副本? [英] How to obtain deep copies of Julia composite types?

查看:58
本文介绍了如何获取Julia复合类型的深层副本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是设置.我有使用其自己的字段和构造函数定义的多个复合类型.让我们在这里显示两个简化的组件:

So here is the setting. I have multiple composite types defined with their own fields and constructors. Lets show two simplified components here:

type component1
    x
    y
end

type component2
    x
    y
    z
end

现在,我想定义一个新类型,以便可以在其中保存大小为K的先前定义的复合类型数组.因此,它是具有两个字段的参数复合类型:一个是整数K,另一个是传递的类型的大小为K的数组.

Now I want to define a new type such that It can save an array of size K of previously defined composite types in it. So it is a parametric composite type with two fields: one is an integer K, and the other is an array of size K of the type passed.

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个组件都引用一个对象并操纵mix.components [k]将影响所有K个组件.在python中,我可以使用deepcopy对此进行补救.但是Julia中的Deepcopy没有为复合类型定义.我该如何解决这个问题?

But this is not the correct way to do it. Because all the K components are referring to one object and manipulating mixture.components[k] will affect all K components. In python I can remedy this with deepcopy. But the deepcopy in Julia is not defined for composite types. How do I solve this problem?

推荐答案

您的特定问题的答案:

在Julia中定义新类型时,通常会将Base中的某些标准方法扩展为新类型,包括deepcopy.例如:

When you define a new type in Julia, it is common to extend some of the standard methods in Base to your new type, including deepcopy. For example:

type MyType
    x::Vector
    y::Vector
end
import Base.deepcopy
Base.deepcopy(m::MyType) = MyType(deepcopy(m.x), deepcopy(m.y))

现在,您可以在MyType的实例上调用deepcopy,您将获得一个新的,真正独立的MyType副本作为输出.

Now you can call deepcopy over an instance of MyType and you will get a new, truly independent, copy of MyType as the output.

注意,我的import Base.deepcopy实际上是多余的,因为我在函数定义中引用了Base,例如Base.deepcopy(m::MyType).但是,我完成了这两项操作,向您展示了从Base扩展方法的两种方法.

Note, my import Base.deepcopy is actually redundant, since I've referenced Base in my function definition, e.g. Base.deepcopy(m::MyType). However, I did both of these to show you the two ways of extending a method from Base.

第二个注意事项,如果您的类型包含很多字段,则可以使用deepcopy遍历这些字段,如下所示:

Second note, if your type has lots of fields, you might instead iterate over the fields using deepcopy as follows:

Base.deepcopy(m::MyType) = MyType([ deepcopy(getfield(m, k)) for k = 1:length(names(m)) ]...)

对您的代码的评论:

首先,Julia的标准做法是大写类型名称,例如Component1而不是component1.当然,您不必这样做,但是...

First, it is standard practice in Julia to capitalize type names, e.g. Component1 instead of component1. Of course, you don't have to do this, but...

其次,来自 Julia文档的性能提示:声明特定于复合类型的字段的类型.请注意,您可以参数化这些声明,例如

Second, from the Julia docs performance tips: Declare specific types for fields of composite types. Note, you can parameterize these declarations, e.g.

type Component1{T1, T2}
    x::T1
    y::T2
end

第三,这是我将如何定义您的新类型:

Third, here is how I would have defined your new type:

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 ])

我的代码与您的代码之间有几个重要的区别.我一次要遍历他们.

There are several important differences here between my code and yours. I'll go through them one at a time.

您的K字段是多余的(我认为),因为它似乎只是components的长度.因此,将length方法扩展为新类型可能更简单,如下所示:

Your K field was redundant (I think) because it appears to just be the length of components. So it might be simpler to just extend the length method to your new type as follows:

Base.length(m::Mixture) = length(m.components)

现在您可以使用length(m),其中mMixture的实例,以获取以前存储在K字段中的内容.

and now you can use length(m), where m is an instance of Mixture to get what was previously stored in the K field.

类型为mixture的内部构造函数是异常的.标准做法是内部构造函数采用与您的类型的字段一对一(依次)对应的参数,然后内部构造函数的其余部分仅执行您希望在初始化您的错误时执行的所有错误检查类型.您偏离了这一点,因为qq不是(不一定)是数组.这种行为最好保留给外部构造函数.那么,我对构造函数做了什么?

The inner constructor in your type mixture was unusual. Standard practice is for the inner constructor to take arguments that correspond one-to-one (in sequence) to the fields of your type, and then the remainder of the inner constructor just performs any error checks you would like to be done whenever initialising your type. You deviated from this since qq was not (necessarily) an array. This kind of behaviour is better reserved for outer constructors. So, what have I done with constructors?

Mixture的内部构造函数除了通过new将参数传递给字段外,实际上没有做任何其他事情.这是因为当前不需要执行任何错误检查(但以后可以轻松添加一些错误检查).

The inner constructor of Mixture doesn't really do anything other than pass the argument into the field via new. This is because currently there aren't any error checks I need to perform (but I can easily add some in the future).

如果要调用此内部构造函数,则需要编写类似m = Mixture{MyType}(x)的内容,其中xVector{MyType}.这有点烦人.因此,我的第一个外部构造函数会使用eltype(x)自动推断{...}的内容.由于我的第一个外部构造函数,我现在可以使用m = Mixture(x)而不是m = Mixture{MyType}(x)

If I want to call this inner constructor, I need to write something like m = Mixture{MyType}(x), where x is Vector{MyType}. This is a bit annoying. So my first outer constructor automatically infers the contents of {...} using eltype(x). Because of my first outer constructor, I can now initialise Mixture using m = Mixture(x) instead of m = Mixture{MyType}(x)

我的第二个外部构造函数对应于您的内部构造函数.在我看来,您要遵循的行为是用components的每个字段中的相同组件初始化Mixture,重复K次.因此,我通过对x的循环理解来做到这一点,只要为x定义了deepcopy方法,该循环就可以工作.如果不存在deepcopy方法,则会出现No Method Exists错误.这种编程称为鸭子编程,在Julia中,使用它通常不会降低性能.

My second outer constructor corresponds to your inner constructor. It seems to me the behaviour you are after here is to initialise Mixture with the same component in every field of components, repeated K times. So I do this with a loop comprehension over x, which will work as long as the deepcopy method has been defined for x. If no deepcopy method exists, you'll get a No Method Exists error. This kind of programming is called duck-typing, and in Julia there is typically no performance penalty to using it.

请注意,我的第二个外部构造函数将调用我的第一个外部构造函数K次,每次,我的第一个外部构造函数将调用我的内部构造函数.在更复杂的情况下,这种方式的嵌套功能将大大减少代码重复.

Note, my second outer constructor will call my first outer constructor K times, and each time, my first outer constructor will call my inner constructor. Nesting functionality in this way will, in more complicated scenarios, massively cut-down on code duplication.

对不起,我知道有很多事情要做.希望对您有所帮助.

Sorry, this is a lot to take in I know. Hope it helps.

这篇关于如何获取Julia复合类型的深层副本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆