Swift中inout与引用类型疑问:类实例为何仍需加&?
为什么Swift中引用类型作为inout参数时仍需加&?
好问题!这确实是Swift里inout参数和引用类型容易搞混的地方,咱们把这个事儿掰明白:
首先先回顾下值类型的情况,比如你提到的swapTwoInts函数:
func swapTwoInts(_ a: inout Int, _ b: inout Int) { let temporaryA = a a = b b = temporaryA }
Int是值类型,默认函数参数是传值拷贝——也就是函数拿到的是原始值的副本,修改副本不会影响原始变量。而inout的作用就是让函数能直接操作原始变量的内存,&就是告诉Swift:“把这个变量的地址传进去,允许函数修改它本身”。
那到了引用类型(比如自定义类)这里,很多人会觉得“既然类是引用传递,直接传实例不就能改了?为啥还要加&?”——这里的关键是要分清修改对象的属性和修改变量的引用是两回事:
- 当你把类实例作为普通参数传递时,函数拿到的是引用的拷贝(也就是指向堆上对象的指针副本)。这时候你可以修改对象的属性(因为指针指向同一个对象),但你没法让原始变量指向一个新的对象——因为你修改的只是指针的副本,原始变量里的指针没变。
- 而
inout参数的作用,就是允许函数修改原始变量本身的存储内容——对于引用类型来说,变量存储的是指向对象的指针,所以inout能让函数把这个指针换成新的(也就是让变量指向另一个对象)。这时候就必须用&来传递,告诉Swift我们要修改的是变量本身的存储,而不是仅仅操作它指向的对象。
举个实际的例子就清楚了:
class Person { var name: String init(name: String) { self.name = name } } // 普通参数:只能修改对象属性,没法改变变量的引用 func updatePersonName(_ person: Person) { person.name = "Alice" // 下面这行代码毫无意义,因为person是引用的拷贝,修改的是副本,原始变量不会变 // person = Person(name: "Bob") } // inout参数:可以修改变量的引用,让它指向新对象 func replacePerson(_ person: inout Person) { person = Person(name: "Bob") // 这会直接修改原始变量的引用 } var myPerson = Person(name: "Charlie") updatePersonName(myPerson) print(myPerson.name) // 输出 "Alice",因为修改的是同一个对象 replacePerson(&myPerson) print(myPerson.name) // 输出 "Bob",因为myPerson现在指向了新的Person实例
总结一下:inout的核心是允许函数修改原始变量的存储内容,不管这个内容是值类型的具体值,还是引用类型的指针。所以当你需要让函数改变引用类型变量的指向时,就必须用&来传递inout参数;如果只是修改对象的属性,那普通参数就足够了,不需要inout和&。
内容的提问来源于stack exchange,提问作者Wike
相关产品推荐
相关产品推荐

