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

查看:17
本文介绍了如何获取 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 docs 性能提示:声明具体复合类型字段的类型.请注意,您可以参数化这些声明,例如

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{我的类型}.这有点烦人.所以我的第一个外部构造函数使用 eltype(x) 自动推断 {...} 的内容.由于我的第一个外部构造函数,我现在可以使用 m = Mixture(x) 而不是 m = Mixture{MyType}(x)Mixture>

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天全站免登陆