Swift 变异函数作为第一个 class 值

Swift mutating Function as first class value

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

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?

这确实有效,但我尝试过类似的方法,但有时它们似乎不稳定。 还需要注意编译器警告。 我怎样才能做到 doing: array2.swapFirstTwo2() 而没有得到 warning/error?

您收到警告(很快就会在 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 参数仅在传递给它们的调用期间有效,因此不能部分应用。

因此,如果您使用 &array2 调用返回的 (inout [Int]) -> () -> (),您将返回一个 () -> (),它现在具有对 array2 的无效引用。尝试调用该函数将产生未定义的行为,因为您正试图在有效的 window 之外改变 inout 参数。

此问题将得到解决 if/when unapplied instance methods get flat signatures,因为 Array.swapFirstTwo2 将计算为 (inout [Int]) -> ()

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

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

var array2 = [1,2,3]
print(array2) // [1, 2, 3]
array2.swapFirstTwo2()
print(array2) // [2, 1, 3]