3

我可以有一个函数来交换数组的前两个元素:

func swapFirstTwo(array: inout [Int]) {
  if array.count >= 2 {
    array.swapAt(0, 1)
  }
}

typealias Swapper = (inout [Int]) -> ()

// And I can have a variable = the function
let swapThem: Swapper = swapFirstTwo

// And it works like this:
var array = [1,2,3]
print(array)
swapThem(&array)
print(array)

// But I'm allergic to Global functions!
// It would be more swifty to have:

extension Array where Element == Int {
  mutating func swapFirstTwo2() {
    if count >= 2 {
      swapAt(0, 1)
    }
  }
}

typealias Swapper2 = (inout [Int]) -> () -> ()

// But when I do this:
let swapThemAgain: Swapper2 = Array.swapFirstTwo2
// I get the error:
// Partial application of 'mutating' method is not allowed; calling the function has undefined behavior and will be an error in future Swift versions

var array2 = [1,2,3]
print(array2)
array2.swapFirstTwo2()
print(array2)
// This in fact works but I've tried similar things and sometimes they appear to be unstable.
// How can I achieve doing: array2.swapFirstTwo2() without getting the error?

这实际上可行,但我尝试过类似的事情,有时它们似乎不稳定。还需要注意编译器警告。我怎样才能做到:array2.swapFirstTwo2() 而不会收到警告/错误?

4

1 回答 1

3

您收到警告(在 Swift 5 模式下很快会出现错误)的原因:

extension Array where Element == Int { 
  mutating func swapFirstTwo2() {
    if count >= 2 {
      swapAt(0, 1)
    }
  }
}

typealias Swapper2 = (inout [Int]) -> () -> ()
let swapThemAgain: Swapper2 = Array.swapFirstTwo2

是因为inout参数仅在传递给它们的调用期间有效,因此不能部分应用。

所以如果你用 调用返回(inout [Int]) -> () -> ()&array2,你会得到一个() -> ()现在有一个无效引用的array2。尝试调用该函数将产生未定义的行为,因为您试图inout在其有效的窗口之外改变一个参数。

如果/当未应用的实例方法获得 flat signatures 时,此问题将得到解决,因为Array.swapFirstTwo2将改为评估为(inout [Int]) -> ().

但与此同时,您可以通过使用闭包来解决此问题:

typealias Swapper2 = (inout [Int]) -> ()
let swapThemAgain: Swapper2 = { $0.swapFirstTwo2() }

var array2 = [1,2,3]
print(array2) // [1, 2, 3]
array2.swapFirstTwo2()
print(array2) // [2, 1, 3]
于 2018-11-02T22:57:19.253 回答