Swift中For-in循环疑问:值类型修改无效原因及修改方法咨询
关于Swift中For-in循环修改值类型对象的问题
嘿,这个问题其实戳中了Swift里值类型和引用类型的核心区别,我来给你掰扯清楚~
为什么第一个循环操作的是副本?
你的Person是结构体(struct),属于Swift里的值类型——值类型的特点就是:只要你把它赋值给另一个变量、或者传递给函数/循环,都会自动生成一份独立的副本。
所以当你写for var person in persons时,循环里的person根本不是原数组里的那个Person实例,只是它的一个拷贝。你在循环里修改person.surname,改的只是这个临时副本,原数组里的对象完全没被碰过,打印出来自然还是nil。
你可以自己加个打印验证:
for var person in persons { person.surname = "surname" print(person.surname) // 这里会输出 "surname",因为副本确实被改了 } print(persons[0].surname) // 但原对象还是 nil
怎么在第一个For-in循环中直接修改原对象?
有几种实用的方法,看你需求选:
方法1:用enumerated()遍历索引(最常用)
enumerated()能同时拿到数组的索引和对应元素,你用索引直接操作原数组就行,写法比你第二个循环更简洁:
for (index, _) in persons.enumerated() { persons[index].surname = "surname" }
方法2:把结构体改成类(如果业务适合)
如果你的Person更适合作为“引用类型”来使用,直接把struct改成class就行:
public class Person { let name: String let age: Int var surname: String? init(name: String, age: Int) { self.name = name self.age = age } }
类是引用类型,遍历的时候for var person in persons拿到的是原对象的引用,修改这个引用指向的对象,原数组里的实例会直接跟着变,第一个循环就能生效了。
方法3:手动同步副本到原数组(进阶写法)
要是你就想用类似第一个循环的遍历方式,也可以先修改副本,再把副本赋值回原数组的对应位置:
persons.indices.forEach { index in var tempPerson = persons[index] tempPerson.surname = "surname" persons[index] = tempPerson }
本质就是手动完成了“取出-修改-放回”的流程,相当于把副本的变化同步回原数组。
最后总结下
- 结构体、枚举这些值类型,赋值/传递时都会拷贝,普通for-in遍历拿到的是副本;
- 类是引用类型,传递的是引用,修改会直接作用于原对象;
- 要修改值类型集合里的原元素,要么通过索引操作,要么改成引用类型,要么手动同步副本。
内容的提问来源于stack exchange,提问作者Aramka
相关产品推荐
相关产品推荐

