使用推!修改不可变的复合类型字段

Using push! to modify immutable composite type fields

以下代码允许修改不可变复合类型的字段,我不确定为什么允许这样做:

struct A
    a :: Vector{Int}
    function A(a :: Vector{Int})
        new(a)
    end
end

myA = A([1,2,3])
@show myA.a # myA.a = [1, 2, 3]
push!(myA.a, 4)
@show myA.a # myA.a = [1, 2, 3, 4]

相反,不允许通过类型方法修改它:

struct A
    a :: Vector{Int}
    function A(a :: Vector{Int})
        new(a)
    end
end

function changeAa!(myA::A, a::Vector{Int})
    myA.a = a
end

myA = A([1,2,3])
changeAa!(myA, [1,2,3,4])

产生:ERROR: LoadError: setfield!: immutable struct of type A cannot be changed(应该如此)。 查看 this question,似乎需要保留该字段指向的对象(push! 就是这种情况),但我仍然不确定如何自己实现它。有人可以详细说明一下吗?谢谢。

I am still unsure how I could implement that myself.

不清楚您要实现什么。能解释一下吗?


myA.a = a 是不允许的,因为它会修改 myA 变量绑定到的对象,这是不允许的。

现在请注意,在 push! 变体中有以下表达式:

push!(myA.a, 4)

相当于写成例如:

b = myA.a
push!(b, 4)

我写这篇文章是为了告诉你重要的是 Vector 是可变的(相对于 struct)。该对象绑定到 myA.a 还是 b 并不重要。 push! 函数只是传递了一个值,它是一个 Vector,因为这个向量是可变的,所以它会改变它。

总而言之:要理解的关键是在 Julia 中你使用的是价值观。值是可变的或不可变的。然后您可以将值绑定到变量名。但是,一个值绑定到什么变量名并不影响这个值的属性。变量名只是一个“标签”,允许您引用值。

这是否澄清了您的疑问?


编辑:

myA 不可变的事实意味着 myA 在内存中的表示不会改变。

myA在内存中的表示是什么?它只是一个指向数组的指针。不能改变的是指针的值,但是指针指向的内存内容是可以改变的。

你想要的功能可以定义为:

function changeAa!(myA::A, a::Vector{Int})
    copy!(myA.a, a)
end