【问题标题】:A Constant Array's Items Can(Cannot) Be Modified If They Are Reference(Value) Types. Why?如果常量数组的项是引用(值)类型,则可以(不能)修改它们。为什么?
【发布时间】: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/2976878array1 不会发生同样的事情,因为 C 是引用类型;变异 value 不会改变数组的内容,仍然只是 3 个引用。
  • @Hamish 感谢您的回复。区别很微妙。值类型如何存储在数组中,以便修改值会导致修改数组?很奇怪,不是吗?就好像当一个数组保存值类型时,数组本身就与它所存储的项目密切相关。
  • @Hamish 正如我最初所说:是否发生了读取->修改->写入?如果是,那么写入是产生数组修改的原因,因此是不允许的。
  • 我不确定我是否完全理解你;如果您指的是 Array 间接存储其内容的事实(因此,从技术上讲,改变元素并不是数组值本身的突变),那么您是非常正确的,但是有点陷入困境在技​​术细节而不是看语义。 Array 具有值语义;数组中元素的突变在语义上等同于分配一个应用了突变的全新数组(+副作用)....
  • ...如果在声明为let 时可以改变数组的元素,Array 将不再具有值语义。 C 具有引用语义;所以改变它的一个属性并不是改变它的值(如果我们认为它的值是对实例的引用)。因此它不是数组的突变,所以当数组是 let 时是允许的。

标签: swift


【解决方案1】:

类是引用类型

与值类型(结构)不同,引用类型在分配给变量或常量或传递给函数时不会被复制。而不是副本,而是使用对相同现有实例的引用。

请参考苹果文档Class & struct

【讨论】:

  • 谢谢。请参阅我对 Hamish 的回复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-21
  • 1970-01-01
  • 2013-07-15
  • 1970-01-01
  • 2018-01-10
相关资源
最近更新 更多