不允许部分应用"变异"方法

Tim*_*len 14 swift

struct MyStruct {
    var count = 0

    mutating func add(amount: Int) {
        count += amount
    }
}

var myStruct = MyStruct()

[1, 2, 3, 4].forEach(myStruct.add)
// Partial application of 'mutating' method is not allowed
Run Code Online (Sandbox Code Playgroud)

为什么不使用forEach这样允许变异方法?我知道我能做到

for number in [1, 2, 3, 4] {
    myStruct.add(number)
}
Run Code Online (Sandbox Code Playgroud)

要么

[1, 2, 3, 4].forEach { myStruct.add($0) }
Run Code Online (Sandbox Code Playgroud)

相反,但都没有那么干净

[1, 2, 3, 4].forEach(myStruct.add)
Run Code Online (Sandbox Code Playgroud)

bob*_*vil 17

值类型的关键是赋值创建副本.此合同还会影响人们如何推理其代码.例如,如果你传入Int一个方法,你可以确信该值不会从你下面改变,即使传入的原始int被发送到另一个线程并在其他地方完成计算.

结构也是如此.这就是为什么在快速定义可能改变'self'的方法时,如果它是一个值类型,你必须将它定义为'mutating'.这说明它会同时用新值重新分配给你的变量.例如,当您使用"3"调用add方法时,您可以将其视为执行类似于以下内容的操作:

var myStruct = MyStruct()
var tmp = myStruct
tmp.count = tmp.count + 3
myStruct = tmp
Run Code Online (Sandbox Code Playgroud)

现在您遇到错误的原因是因为部分应用变异函数会破坏该合同.如果你能够保存一个类似的闭包let myStructAdd = myStruct.add,那么稍后你可以调用myStructAdd(3)它,它会尝试更改myStruct.这将为值类型提供引用语义,因为现在您可以在以后更改myStruct,即使是从不同的方法.

简而言之,swift通过为代码可读性提供"变异"方法为您提供了便利,但需要注意的是它必须同时发生,以免破坏值类型契约.

  • `let myStructAdd = myStruct.add` 确实不起作用,但`let myStructAdd = { myStruct.add($0) }` 确实有效。这有什么不同?它仍然允许我调用 `myStructAdd(3)` 来改变结构的值。 (2认同)
  • 令人遗憾的是,Swift并不聪明地注意到`forEach`的closure参数是一个`@noescape`,因此闭包将无法逃避方法调用的范围,因此意味着不应该'是在'mutating`函数中传递的任何问题. (2认同)