注意:以下内容为通俗易懂的描述。
虽然以下解释在代码细节上不是非常准确,但被一位实际从事Swift开发的人审查后认为已足够作为基本解释。
现在我想试着简单明了地回答一个问题:“为什么我们可以在没有修改关键字的情况下更改结构体参数,却需要将结构体函数标记为“mutating”呢?”
大致上来讲,这与保持Swift快速(swift)的理念有很多关系。
你可以把它看作是管理物理地址的问题。当您更改您的地址时,如果有很多人有您当前的地址,您必须通知所有人您已经搬家了。但是,如果没有人知道您的当前地址,您可以随时搬到任何地方,无需通知任何人。
在这种情况下,Swift就像邮局。如果有很多人和很多联系人经常搬家,那么它的开销就会非常高。它必须支付一大批员工来处理所有这些通知,这个过程需要耗费大量时间和精力。这就是为什么Swift的理想状态是让城镇中的每个人都尽可能地少有联系人。那么它就不需要一个大型的员工来处理地址更改,并且可以更快、更好地完成其他所有事情。
这也是为什么Swift中关于值类型和引用类型的问题备受推崇。从本质上讲,引用类型在各个方面都会增加“联系人”的数量,而值类型通常不需要超过几个联系人。因此,值类型更具有“Swift”性质。
回到细节问题:结构体。在Swift中,结构体非常重要,因为它们可以做大部分对象能够做的事情,但它们是值类型。
让我们继续用物理地址的比喻来想象一个住在someObjectVille
中的misterStruct
。这个比喻有点混乱,但我认为它仍然有帮助。
因此,为了模拟更改struct
变量,假设misterStruct
有绿色头发,并收到了换成蓝色头发的指令。就像我说的那样,这个比喻有点混乱,但所发生的事情有点像是老人搬出去,一个带着蓝色头发的新人搬进来,这个新人开始称自己为misterStruct
。没有人需要收到地址更改通知,但如果有人查看该地址,他们会看到一个有蓝色头发的人。
现在让我们模拟在struct
上调用函数时会发生什么。在这种情况下,就像misterStruct
收到诸如changeYourHairBlue()
之类的指令一样。所以邮局将指示传递给misterStruct
,“去把你的头发染成蓝色,告诉我什么时候完成。”
如果他按照以前的相同例程进行,如果他在直接更改变量时所做的事情仍然是一样的话,那么misterStruct
将会搬出自己的房子并呼叫一个新的蓝发人。但这是问题。
指令是“去把你的头发染成蓝色,告诉我什么时候完成”,但收到该指令的是绿发的那个家伙。在蓝发家伙搬进来之后,仍然必须发送“作业完成”通知。但蓝发家伙一无所知。
[为了使这个比喻更加混乱,技术上发生的是绿发家伙在搬出去后,他立即自杀了。因此,他也不能通知任何人任务已经完成。]
为了避免这个问题,在这种情况下,Swift必须直接进入该地址的房屋并实际更改当前居住者的头发。这是一个完全不同的过程,不同于只是派遣一个新人进去。
这就是为什么Swift希望我们使用"mutating"关键字的原因!
对于必须引用结构体的任何内容,最终结果看起来都一样:房屋的居民现在有蓝色的头发。但是实现它的过程实际上是完全不同的。它看起来在做相同的事情,但实际上它正在做一个非常不同的事情。它是一件Swift结构体通常从不会做的事情。
因此,为了帮助可怜的编译器,并不让它自己解决每个结构体函数是否会改变结构体,我们被要求要用"mutating"关键字。
基本上,为了帮助Swift保持迅速,我们所有人都必须尽自己的一份力。 :)
const
关键字(普通方法不能在常量实例上使用)。Swift 也采用了与之相反的默认设置:方法默认具有“常量 this”,如果必须禁止在常量实例上使用,则需要标记为另外一种方式。 - Analog Filelet
值将永远是不可变的。你只能在初始化器中分配它们一次。 - eonil