Swift - 如何在遍历结构对象时改变它

Swift - How to mutate a struct object when iterating over it

我还是不太清楚struct复制或引用的规则。

我想在从数组迭代结构对象时改变它: 例如在这种情况下我想改变背景颜色 但是编译器对我大吼大叫

struct Options {
  var backgroundColor = UIColor.blackColor()
}

var arrayOfMyStruct = [MyStruct]

...

for obj in arrayOfMyStruct {
  obj.backgroundColor = UIColor.redColor() // ! get an error
}

struct 是值类型,因此在 for 循环中你正在处理一个副本。

作为测试,您可以试试这个:

Swift 3:

struct Options {
   var backgroundColor = UIColor.black
}

var arrayOfMyStruct = [Options]()

for (index, _) in arrayOfMyStruct.enumerated() {
   arrayOfMyStruct[index].backgroundColor = UIColor.red
}

Swift 2:

struct Options {
    var backgroundColor = UIColor.blackColor()
}

var arrayOfMyStruct = [Options]()

for (index, _) in enumerate(arrayOfMyStruct) {
    arrayOfMyStruct[index].backgroundColor = UIColor.redColor() 
}

这里只是枚举索引,直接访问数组中存储的值

希望对您有所帮助。

我在一些代码中看到了这个方法,它似乎有效

for (var mutableStruct) in arrayOfMyStruct {
  mutableStruct.backgroundColor = UIColor.redColor()
}

对于Swift3,使用enumerated()方法。

例如:

for (index, _) in arrayOfMyStruct.enumerated() {
  arrayOfMyStruct[index].backgroundColor = UIColor.redColor() 
}

元组还包含对象的副本,因此您可以使用 for (index, object) 来直接访问对象,但由于它是副本,因此您无法以这种方式改变数组,并且应该使用 index 来这样做。直接引用 documentation:

If you need the integer index of each item as well as its value, use the enumerated() method to iterate over the array instead. For each item in the array, the enumerated() method returns a tuple composed of an integer and the item.

您可以使用 Array.indices:

for index in arrayOfMyStruct.indices {
    arrayOfMyStruct[index].backgroundColor = UIColor.red
}

您正在使用 struct 对象,这些对象在使用 for in 循环时被复制到局部变量。数组也是一个 struct 对象,所以如果你想改变数组的所有成员,你必须创建由原始对象的修改副本填充的原始数组的修改副本。

arrayOfMyStruct = arrayOfMyStruct.map { obj in
   var obj = obj
   obj.backgroundColor = .red
   return obj
}

可以通过添加这个数组扩展来简化。

Swift 4

extension Array {
    mutating func mutateEach(by transform: (inout Element) throws -> Void) rethrows {
        self = try map { el in
            var el = el
            try transform(&el)
            return el
        }
     }
}

用法

arrayOfMyStruct.mutateEach { obj in
    obj.backgroundColor = .red
}

另一种不用每次都写下标表达式的方法

struct Options {
    var backgroundColor = UIColor.black
}

var arrayOfMyStruct = [Options(), Options(), Options()]

for index in arrayOfMyStruct.indices {
    var option: Options {
        get { arrayOfMyStruct[index] }
        set { arrayOfMyStruct[index] = newValue }
    }
    option.backgroundColor = .red
}