[英]Why does my struct become immutable in a method chain?
在Swift中,我试图实现一个方法“tap”,类似于Ruby中存在的方法。
我想出了以下示例代码:
private protocol Tap {
mutating func tap(_ block: (inout Self) -> Void) -> Self
}
private extension Tap {
mutating func tap(_ block: (inout Self) -> Void) -> Self {
block(&self)
return self
}
}
extension Array: Tap {}
var a = Array(repeating: "Hello", count: 5)
a.tap {
$0.append("5")
}.tap {
$0.append("7")
}
print(a) // (Expected) => ["Hello", "Hello", "Hello", "Hello", "Hello", "5", "7"]
我不太熟悉变异函数,inout参数或Swift,但上面的代码看起来应该对我有用。 当它没有包含在方法链中时, tap
按预期工作。 当我将它作为方法链的一部分包含在内时,就像上面的例子一样,Swift编译器抱怨:
不能在不可变值上使用变异成员:函数调用返回不可变值
任何人都可以向我解释为什么这不起作用? 任何人都可以提供有效的解决方案并解释该解决方案的原因
另一个示例用法是:
let user = User(fromId: someId).tap {
$0.firstName = someFirstName
$0.lastName = someLastName
}
tap
是Ruby的便利之物。 我主要是想了解为什么我的函数中的类型不正确。
return self
返回原始数组的副本,而不是原始数组本身。 在将此副本存储为var
,不能对其进行变异。 所以,这将工作:
var b = a.tap {
$0.append("5")
}
b.tap {
$0.append("7")
}
但不是先将b
存储为var
。 当然,你不会首先创建一个b
,你只a
反复使用,就像你已经指出的那样。
所以,问题是你可以完成一次tap
,但不能连接tap
。 这是因为self
的返回是隐式不可变的,并且您不能在不可变值上调用变异函数。 将tap
更改为非变异函数可以获得您想要的内容:
private extension Tap {
func tap(_ block: (inout Self) -> Void) -> Self {
let copy = self
block(©)
return copy
}
}
var a = Array(repeating: "Hello", count: 5)
a = a.tap({$0.append("5")}).tap({$0.append("7")})
因为每次调用tap(
返回由给定块修改的原始副本,你可以在不可变类型上调用它。这意味着你可以链接。
唯一的缺点是新的a =
开头。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.