[swift]为什么不断约束从结构属性实例而不是类的实例吗?

标签: Swift
发布时间: 2017/3/6 22:54:39
注意事项: 本文中文内容可能为机器翻译,如要查看英文原文请点击上面连接.

当我试图更改 ID 属性的 byValueObj 实例,我收到一个错误,告诉我我不能将属性指定为一个常数,即使该属性是一个变量。然而,我可以做它对类实例。我善良的知道它也许已经跟通过值和通过引用机制。但我没有一个非常明确的和正确的认识。有人可以为我解释吗?谢谢你。

struct CreatorValue{
    var ID = 2201
}
class CreatorRefer{
    var ID = 2203
}

let byValueObj = CreatorValue()
let byReferObj = CreatorRefer()

byValueObj.ID = 201 //Error: cannot assign to property: 'byValueObj' is a 'let' constant
byReferObj.ID = 203 //works fine here

解决方法 1:

结构在 Swift值类型,这意味着该更改的属性的值 struct 实例 (是通过 mutating 方法或通过直接做它) 更改该实例的整个值

如果你考虑一个值类型的内存中表示形式,它通常会存储其内容内联— — 也就是说,内存中的表示形式︰

struct Foo {
    var bar = 23
    var baz = 59
}

// ...

let foo = Foo()

通常看起来像这样︰

|  foo (a Foo instance) |
|<--------------------->|
|0x2A       |0x32       |0x3A
|  bar: Int | baz : Int |
|     23    |     59    |

因此改变属性的值 bar 更改的整个值 Foo 实例 — — 意味着你需要将标记类型的变量 Foo 作为 var 为了能变异的实例 (该实例的属性,例如更改) 的值。

可能更简单的方法想值语义是想象的该值类型的实例不直接发生突变,而是替换为相同类型的新实例。例如,你可能觉得这个︰

struct Foo {
    var bar = 23
    var baz = 59
}

// ...

let foo = Foo()
foo.bar = 7 // illegal

作为这样做︰

let foo = Foo()

var fooCopy = foo // temporary mutable copy of foo.

fooCopy.bar = 7   // mutate one or more of the of the properties

foo = fooCopy     // re-assign back to the original (illegal as foo is declared as
                  // a let constant)

你可以清楚地看到在这里 — — 这段代码是非法的。您不能分配 fooCopyfoo — — 因为它有 let 恒定。因此,您不能更改声明为值类型的属性的 let ,并将因此需要使 var

(请注意,以前版本的这个答案指出上述模型实际上是实际发生 — — 其中, SIL 生成看完,原来是假。结构可以在事实有突变直接通过其属性 struct_element_addr store SIL 说明.)


原因你可以更改的可变属性 let 恒定实例是,类是引用类型。因此被 let 常数只确保引用保持不变。变异及其属性并不以任何方式影响你对它们的引用 — — 你仍指内存中的同一位置。

你能想到的引用类型像路标,因此像这样的代码︰

class Foo {
    var bar = 23
    var baz = 59
}

// ...

let referenceToFoo = Foo()

你能想到的像这样的内存表示形式︰

|    referenceToFoo     |  --->  | Underlying Foo instance |
| (a reference to 0x2A) |        |<----------------------->|
                                 |0x2A       |0x32         |0x3A
                                 |  bar: Int |  baz : Int  |
                                 |     23    |      59     |

和当你变异属性︰

referenceToFoo.bar = 203

引用 ( referenceToFoo )本身不受影响 — — 你仍指向内存中的同一位置。它是改变 (也就是说基础实例突变) 的基本实例的属性︰

|    referenceToFoo     |  --->  | Underlying Foo instance |
| (a reference to 0x2A) |        |<----------------------->|
                                 |0x2A       |0x32         |0x3A
                                 |  bar: Int |  baz : Int  |
                                 |    203    |      59     |

只有当你试图分配到一个的引用 referenceToFoo 将编译器给你一个错误,因为你试图变异引用本身︰

// attempt to assign a new reference to a new Foo instance to referenceToFoo.
// will produce a compiler error, as referenceToFoo is declared as a let constant.
referenceToFoo = Foo()

因此,你需要使 referenceToFoo var ,使这项任务的法律。

官方微信
官方QQ群
31647020