Swift中get-only下标返回的实例为何无法为其属性赋值?
问题触发原因
- 你定义的
Student是值类型,对值类型属性的赋值本质是对整个值实例的替换。你通过下标返回Student?之后尝试修改其属性,相当于要修改下标返回的值并写回StudentStore的students数组中。 - 你当前实现的
StudentStore下标只有get逻辑,属于只读下标,不支持修改返回值后写回原存储的操作,因此编译器直接抛出报错。 - 额外补充:数组的
first属性本身也是只读的,直接返回它的结果天然不支持修改后同步到原数组。
可行解决方法
方案1:给下标补充setter实现(最推荐,不改动原有数据结构设计)
给下标增加写逻辑,赋值时自动替换数组中对应位置的实例:
class StudentStore { var students = [Student]() subscript(id: String) -> Student? { get { students.first(where: { $0.id == id } ) } set { // 找到对应索引,用新值替换原有实例 guard let index = students.firstIndex(where: { $0.id == id }), let newValue = newValue else { return } students[index] = newValue } } }
修改完成后原来的赋值代码studentStore["2014901001"]?.attendance = 1可以正常运行。
方案2:将Student改为引用类型(class)
如果你的业务场景适合把Student设计为引用类型,只需要把struct Student改为class Student即可:
class Student { var id: String var attendance = 0 var absence = 0 init(id: String) { self.id = id } }
此时下标即使是只读的,返回的也是Student实例的引用,修改引用指向对象的属性不需要修改下标返回值本身,不会触发报错。
方案3:直接操作数组索引(无需修改原有封装)
如果不想改动StudentStore和Student的定义,可以直接找到目标元素的索引后修改:
if let index = studentStore.students.firstIndex(where: { $0.id == "2014901001" }) { studentStore.students[index].attendance = 1 }
内容的提问来源于stack exchange,提问作者Fawzi Rifai
相关产品推荐
相关产品推荐

