【发布时间】:2017-12-14 00:23:47
【问题描述】:
请查看以下代码并注意最后一行的编译器错误:
class C {
var value: Int
init( _ value: Int) { self.value = value }
}
let array1 = [C(1), C(2), C(3)]
array1[0].value = 4
struct S {
var value: Int
}
let array2 = [S(value: 1), S(value: 2), S(value: 3)]
array2[0].value = 4 // Error: Cannot assign to property: 'array2' is a 'let' constant
从编译器错误中,我想得出以下结论:索引 0 处的项目正在从 array2 中读取、修改,然后写回 array2。还有什么可以产生试图修改array2的结果?但是,如果我的推理是正确的,那么为什么 array1 不会发生同样的事情呢?
【问题讨论】:
-
有些相关:stackoverflow.com/q/38010936/2976878。
array1不会发生同样的事情,因为C是引用类型;变异value不会改变数组的内容,仍然只是 3 个引用。 -
@Hamish 感谢您的回复。区别很微妙。值类型如何存储在数组中,以便修改值会导致修改数组?很奇怪,不是吗?就好像当一个数组保存值类型时,数组本身就与它所存储的项目密切相关。
-
@Hamish 正如我最初所说:是否发生了读取->修改->写入?如果是,那么写入是产生数组修改的原因,因此是不允许的。
-
我不确定我是否完全理解你;如果您指的是
Array间接存储其内容的事实(因此,从技术上讲,改变元素并不是数组值本身的突变),那么您是非常正确的,但是有点陷入困境在技术细节而不是看语义。Array具有值语义;数组中元素的突变在语义上等同于分配一个应用了突变的全新数组(+副作用).... -
...如果在声明为
let时可以改变数组的元素,Array将不再具有值语义。C具有引用语义;所以改变它的一个属性并不是改变它的值(如果我们认为它的值是对实例的引用)。因此它不是数组的突变,所以当数组是let时是允许的。
标签: swift