为什么常量约束结构实例而不是类实例的属性? [英] Why constant constraints the property from a structure instance but not the class instance?

查看:37
本文介绍了为什么常量约束结构实例而不是类实例的属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我尝试更改 byValueObj 实例的 ID 属性时,我收到一个错误,告诉我我无法分配给常量的属性,即使属性是一个变量.但是,我可以在类实例上做到这一点.我有点知道它可能与按值和按引用机制有关.但我对它的认识不是很清楚和正确.有人可以为我解释一下吗?谢谢.

When I trying to change the ID property of the byValueObj instance, I received an error that told me I cannot assign to the property of a constant, even though the property is a variable. However, I can do it on a class instance. I kind of knowing that it maybe has something to do with the by value and by reference mechanism. But I don't have a very clear and correct understanding of it. Can someone explain it for me? Thanks.

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 中的结构是 值类型 – 从语义上讲,值(即值类型的实例")是不可变的.

Structures in Swift are value types – and, semantically speaking, values (i.e 'instances' of value types) are immutable.

值类型的突变,无论是通过直接改变属性的值,还是通过使用mutating方法,都相当于只是分配了一个全新的保存它的变量的值(加上突变触发的任何副作用).因此持有它的变量需要是一个var.属性观察者围绕值类型的行为很好地展示了这种语义,iGodric 指出.

A mutation of a value type, be it through directly changing the value of a property, or through using a mutating method, is equivalent to just assigning a completely new value to the variable that holds it (plus any side effects the mutation triggered). Therefore the variable holding it needs to be a var. And this semantic is nicely showcased by the behaviour of property observers around value types, as iGodric points out.

所以这意味着你可以这样想:

So what this means is that you can think of this:

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 常量.因此,您不能更改声明为 let 的值类型的属性,因此需要将其设为 var.

And as you can clearly see – this code is illegal. You cannot assign fooCopy back to foo – as it's a let constant. Hence, you cannot change the property of a value type that is declared as a let, and would therefore need make it a var.

(值得注意的是,编译器实际上并没有经过这个palaver;它可以直接改变结构的属性,这可以通过查看SIL 生成.但这不会改变值类型的语义.)

(It's worth noting that the compiler doesn't actually go through this palaver; it can mutate the properties of structures directly, which can be seen by looking at the SIL generated. This doesn't change the semantics of value types though.)

之所以可以更改 let 常量 class 实例的可变属性,是因为类是引用类型.因此,作为 let 常量只能确保 reference 保持不变.改变它们的属性不会以任何方式影响您对它们的引用——您仍然指的是内存中的相同位置.

The reason you can change a mutable property of a let constant class instance, is due to the fact that classes are reference types. Therefore being a let constant only ensures that the reference stays the same. Mutating their properties doesn't in any way affect your reference to them – you're still referring to the same location in memory.

您可以将引用类型想象为路标,因此代码如下:

You can think of a reference type like a signpost, therefore code like this:

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

// ...

let referenceToFoo = Foo()

你可以这样想内存表示:

you can think of the memory representation like this:

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

当你改变一个属性时:

referenceToFoo.bar = 203

引用(referenceToFoo)本身不受影响——你仍然指向内存中的相同位置.底层实例的属性发生了变化(意味着底层实例发生了变异):

The reference (referenceToFoo) itself isn't affected – you're still pointing to the same location in memory. It's the property of the underlying instance that's changed (meaning the underlying instance was mutated):

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

只有当您尝试将 new 引用分配给 referenceToFoo 时,编译器才会给您一个错误,因为您正在尝试改变引用本身:

Only when you attempt to assign a new reference to referenceToFoo will the compiler give you an error, as you're attempting to mutate the reference itself:

// 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 以使此分配合法.

You would therefore need to make referenceToFoo a var in order to make this assignment legal.

这篇关于为什么常量约束结构实例而不是类实例的属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆