为什么我的结构在方法链中变得不可变?

时间:2019-01-24 01:16:19

标签: swift struct value-type

在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的一种便利工具。我主要是想了解为什么函数中的类型无法正常工作。

1 个答案:

答案 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(&copy)
        return copy
    }
}

var a = Array(repeating: "Hello", count: 5)

a = a.tap({$0.append("5")}).tap({$0.append("7")})

由于tap(的每次调用都返回由给定块修改的原始副本,因此可以在不可变类型上调用它。这意味着您可以链接。

唯一的缺点是开头的新a =