forEach结果$ 0是不可变的错误

时间:2016-09-05 12:44:35

标签: arrays swift foreach

protocols.forEach { $0.prop = nil }

结果:

Cannot assign to property: '$0' is immutable

我解决了这个问题:

protocols.forEach
{
    var protocol = $0

    protocol.prop = nil
}

但是为什么编译器可以用这个呢?我希望它可以解决这个问题。

2 个答案:

答案 0 :(得分:30)

您有一系列实现协议的项目。如果您没有告诉Swift这是class协议,它会认为它可以由struct实现。

forEach循环中,您基本上会有一个let变量(默认情况下称为$0)依次分配给数组中的每个值。如果您有一个对象数组(类的实例),则可以修改该项的属性。如果您有一个struct项的数组,那么这些项将是不可变的。如果您有一组实现协议的项目,那么除非您在协议定义中添加struct,否则Swift会将它们视为限制性更强的: class

例如:

protocol Xyzzy: class {
    var prop: Int? { get set }
}

class Fred: Xyzzy, CustomStringConvertible {
    var description: String { return "\(prop)" }
    var prop: Int? = 17
}

let objects: [Xyzzy] = [Fred(), Fred(), Fred()]

print(objects)  //  [Optional(17), Optional(17), Optional(17)]

objects.forEach { $0.prop = nil }

print(objects)  // [nil, nil, nil]

您的解决方法:

protocols.forEach
{
    var protocol = $0

    protocol.prop = nil
}

适用于类对象,因为它会创建一个指向该对象的新var指针,然后允许您修改该对象。请注意,此解决方法仅适用于类的实例。如果您的协议是由struct实现的,那么新的var将是struct项的新副本,并且数组中的原始副本将不会更改。

答案 1 :(得分:8)

如何更改 ArrayStructs

对于每个元素:

itemsArray.indices.forEach { itemsArray[$0].someValue = newValue }

对于特定元素:

itemsArray.indices.filter { itemsArray[$0].propertyToCompare == true }
                  .forEach { itemsArray[$0].someValue = newValue }