在Swift中,我试图实现与Ruby中存在的方法类似的“点击”方法。
我提出了以下示例代码:
addActionListener()
我对突变函数,inout参数或一般的Swift并不是很熟悉,但是上面的代码看起来应该对我有用。 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"]
在未包含在方法链中时会按预期工作。当我将其作为方法链的一部分包括在内时,如上例所示,Swift编译器会抱怨:
不能对不可变值使用变异成员:函数调用返回不可变值
有人可以向我解释为什么这行不通吗?谁能提供可行的解决方案并解释该解决方案为何起作用?
另一个示例用法是:
tap
let user = User(fromId: someId).tap {
$0.firstName = someFirstName
$0.lastName = someLastName
}
是来自Ruby的一种便利工具。我主要是想了解为什么函数中的类型无法正常工作。
答案 0 :(得分:1)
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 =
。