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

mea*_*ers 18 arrays foreach swift

protocols.forEach { $0.prop = nil }
Run Code Online (Sandbox Code Playgroud)

结果是:

Cannot assign to property: '$0' is immutable
Run Code Online (Sandbox Code Playgroud)

我解决了这个问题:

protocols.forEach
{
    var protocol = $0

    protocol.prop = nil
}
Run Code Online (Sandbox Code Playgroud)

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

vac*_*ama 35

您有一组实现协议的项目.如果你不告诉Swift这是一个class协议,它将假设它可以由a实现struct.

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

例如:

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]
Run Code Online (Sandbox Code Playgroud)

你的解决方法:

protocols.forEach
{
    var protocol = $0

    protocol.prop = nil
}
Run Code Online (Sandbox Code Playgroud)

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

  • 很好的答案有助于更深入地了解Swift。谢谢! (2认同)
  • @0xxxD,在 Swift 中,所有类型在编译时都是已知的。结构体和类可以采用的协议被视为更具限制性的结构体,因为 Swift 不会在运行时做出动态决定。是的结构是值类型。当它们被分配给一个 let 常量(例如循环变量)时,所有属性都是不可变的。将协议声明为 `class` 告诉 Swift 你只会将它与类一起使用,并且 Swift 在编译时会将该协议类型的变量视为引用。 (2认同)

Den*_*kin 11

如何改变Array的Structs

对于每个元素:

itemsArray.indices.forEach { itemsArray[$0].someValue = newValue }
Run Code Online (Sandbox Code Playgroud)

对于特定元素:

itemsArray.indices.filter { itemsArray[$0].propertyToCompare == true }
                  .forEach { itemsArray[$0].someValue = newValue }
Run Code Online (Sandbox Code Playgroud)

  • 我差点就用了这个,但我不得不对未来的自己或其他人发生的事情发表评论。它也感觉没那么快。所以发现有“枚举”作为序列协议的一部分。我用它来代替。`itemsArray.enumerated().map` Map 现在有两个默认参数 $0 是索引,$1 是值。或 `itemsArray.enumerated().map{ 索引, //morecode 中的值 }` (2认同)