我正在尝试修改数组中的struct元素。我发现可以通过按索引访问(迭代)该结构来实现,但是如果使用“ for in”循环或forEach {},则无法实现。
struct Person
{
var age = 0
var name = "James"
}
var personArray = [Person]()
personArray += [Person(), Person(), Person()]
personArray.forEach({$0.age = 10}) // error: "Cannot assign to property: '$0' is immutable"
for person in personArray {
person.age = 10 // error: "Cannot assign to property: 'person' is a 'let' constant"
}
for index in personArray.indices {
personArray[index].age = 10 // Ok
}
有人可以解释吗?
答案 0 :(得分:3)
如其他答案所述,您不能在for-in
循环或.forEach
方法中进行变异。
您可以使用简短明了的最后一种表述:
for index in personArray.indices {
personArray[index].age = 10
}
或完全更改原始personArray
:
personArray = personArray.map { person in
var person = person // parameter masking to allow local mutation
person.age = 10
return person
}
请注意,第二个选项似乎效率较低,因为它每次都会创建一个Person
的新实例,但是Swift对于这些情况似乎进行了优化。 Time Profiler报告说,第二种方法的操作速度快了NEAR 2倍,数组选项为1 000 000 Person
s。
如果您确实希望使用.forEach
方法的变异副本,请在MutableCollection
上使用扩展名:
extension MutableCollection {
mutating func mutateEach(_ body: (inout Element) throws -> Void) rethrows {
for index in self.indices {
try body(&self[index])
}
}
}
这是等效于您的第一个公式的数组突变包装,您可以按预期使用它:
personArray.mutateEach { $0.age = 10 }
答案 1 :(得分:1)
在Swift中,结构是值类型。在for或foreach循环中,人员项目是一个值,如果可变,则您将只更改原始副本,而不是按预期更改原始副本。
如果您确实想要在循环内对 struct 进行可更新的引用,请添加var关键字,但请记住,您正在更新的不是原始副本。
for var person in personArray {
person.age = 10 // updates a copy, not the original
}
按对比类别是引用类型,在循环中,每个项目都是对原始内容的引用。现在,更新此参考值将更新原始值。
将Person的定义更改为class而不是struct,它将按预期工作。 有关完整的说明,请参见https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html