如何在 swift 中使用可变闭包?

How to use a variadic closure in swift?

在 Swift 的闭包中是否有使用可变参数列表的正确方法?

在 swift 中,我注意到我可以声明一个带有可变参数列表的函数,就像这样

protocol NumberType: Comparable, IntegerLiteralConvertible, IntegerArithmeticType {}
extension Int: NumberType {}

extension SequenceType where Generator.Element: NumberType {
    func satisfy(closure:(args: Generator.Element...) -> ()) {
        // Do something
        closure(args: 1, 2, 3)
    }
}

构建得很好。当我尝试使用函数时:

[1, 2].satisfy { (args) in
    print (args)
}

Xcode 设法像我预期的那样自动完成,但是在关闭 args 后的括号后,Xcode 中的所有语法突出显示都消失了,我看到一条消息 "Command failed due to signal: Segmentation Fault: 11",它似乎只是意味着 Xcode 非常困惑。

对于上下文,我曾计划看看 Swift 是否可以编写一个函数,该函数可以 return 根据可变数量的参数(映射到获得蛮力答案)。这将是一种测试问题答案的简单方法,例如 "Given an array of Ints, find all combinations which satisfy the equation a^3 + b^3 = c^3 + d^3" 和

let answer = array.satisfy ({ return pow([=13=], 3) + pow(, 3) == pow(, 3) + pow(, 3) })

反对更优的解决方案。

"Return all the 2s" 就是

let answer = array.satisfy ({ return [=14=] == 2 })

一个for循环

编译器limitation/bug 具有单表达式闭包的参数类型推断

我认为这是编译器 w.r.t 中的当前限制 (/bug) 造成的。使用可变参数推断单行闭包中的参数类型,参见例如以下问答

  1. Why can't I use .reduce() in a one-liner Swift closure with a variadic, anonymous argument?

Swift 2.1 中的 inout 参数也存在类似问题(但不再出现在 2.2 中),如以下线程

中所述

查看线程 1。并试图找到在 Swift JIRA 中标记的所述错误,然而,似乎线程 1 的 OP 似乎从未为此提交过错误,毕竟。可能我只是还没有找到现有的错误报告,但如果 none 存在,应该提交一份。


当前的解决方法

在编译器的闭包参数类型推断赶上之前,可能的解决方法是

  • 将闭包扩展到单行主体之外

    // ...
    
    [1, 2].satisfy { (args) in
        () // dummy
        print (args) // [1, 2, 3]
    }
    
  • 或者,明确包含 args 的类型,例如

    [1, 2].satisfy { (args: Int...) in
        print (args) // [1, 2, 3]
    }
    

    请注意,在上面的示例中,Generator.Element 解析为 Int


Swift 3.0-dev

的当前状态

如上所述,奇怪的是,这个错误

  • inout: 显然不再出现在 Swift 2.2 或 Swift 3.0-dev 中用于 inout 参数, w.r.t。

    中描述的问题
    • 它可能已修复,因为 bug [SR-7] 已解决 (-> Swift 2.2)
    • 不过,好像是回归2.2->3.0-dev,w.r.t。 inout 个参数的类型推断,如 bug report [SR-892] 中所报告。例如。以下代码片段在 Swift 2.2 中有效,但在 3.0-dev 中无效(来自错误报告 [SR-7] 的最小修改片段)

      func f(inout a: Int) {}
      let g = { x in f(&x) }  // OK 2.2, crashes 3.0-dev
      
  • variadic: 仍然存在于 Swift 2.2 以及 Swift 3.0-dev 中用于可变参数(这个线程和Q&A 1. above).

    • 一个更简洁的错误示例:

      let a: (Int...) -> () = { (args) in print(args) }         // bug: crashes
      let b: (Int...) -> () = { (args: Int...) in print(args) } // explicitly state argument type, OK
      let c: (Int...) -> () = { (args) in (); print(args) }     // extend to more than single line closure, OK
      

(对于 Swift 3.0-dev,使用 IBM Swift Sandbox running Swift 3.0-dev.

测试