Swift 为什么我的结构在方法链中变得不可变?
在Swift中,我试图实现一个与Ruby中存在的方法类似的方法“tap” 我提出了以下示例代码:Swift 为什么我的结构在方法链中变得不可变?,swift,struct,value-type,Swift,Struct,Value Type,在Swift中,我试图实现一个与Ruby中存在的方法类似的方法“tap” 我提出了以下示例代码: private protocol Tap { mutating func tap(_ block: (inout Self) -> Void) -> Self } private extension Tap { mutating func tap(_ block: (inout Self) -> Void) -> Self { block(&
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,但上面的代码对我来说应该很有用<代码>点击在未包含在方法链中时按预期工作。当我将其作为方法链的一部分包含时,如上例所示,Swift编译器会抱怨:
无法对不可变值使用mutating成员:函数调用返回不可变值
有人能解释一下为什么这不起作用吗?谁能提供一个有效的解决方案并解释为什么该解决方案有效
编辑:
另一个示例用法是:
let user = User(fromId: someId).tap {
$0.firstName = someFirstName
$0.lastName = someLastName
}
tap
是Ruby提供的一种便捷功能。我主要感兴趣的是理解为什么函数中的类型工作不正常。返回self返回原始数组的副本,而不是原始数组本身。在将此副本存储为var
之前,无法对其进行变异。因此,这将起作用:
var b = a.tap {
$0.append("5")
}
b.tap {
$0.append("7")
}
但必须先将b
存储为var
。当然,您首先不会创建b
,您只需重复使用a
,正如您已经指出的那样
因此,问题是您可以完成tap
一次,但不能链接tap
s。这是因为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=
在开头。有趣的问题…我很想听到完整的答案,但这里有一些初步的想法,虽然它似乎工作正常,但可能会对一些代码产生一些意想不到的后果。当您将&self传递到块时,因为它是一个变异函数,所以根据块改变self的值。但是,返回self也会生成数组的单独副本。因此,如果设置b=a.tap{…},将对“a”进行变异,您将在“b”中收到它的一个独立副本。看起来您不会同时进行这两种操作,而只是在适当的位置对“a”进行变异,对吗?根据本文,我认为像数组这样的结构不可能实现所需的行为。