当我尝试更改实例的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
Swift中的结构是值类型–从语义上讲,值(即值类型的“实例”)是不可变的。
值类型的突变,无论是直接更改属性的值,还是通过使用mutating
方法,都相当于为保存该变量的变量分配了一个全新的值(加上该突变触发的任何副作用)。因此,保存该变量的变量必须为var
。正如iGodric指出的那样,属性值周围的属性观察者的行为很好地展示了这种语义。
因此,这意味着您可以想到以下几点:
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)
如您所见,此代码是非法的。您不能将其赋值fooCopy
给foo
-这是一个let
常数。因此,您不能更改声明为a的值类型的属性,let
因此需要将其设置为a var
。
(值得注意的是,编译器实际上并没有经过该操作程序;它可以直接更改结构的属性,这可以通过查看生成的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
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句