3

在 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 是否可以编写一个函数,该函数可以根据可变数量的参数返回答案(映射到获得蛮力答案所需的 for 循环数)。这将是一种测试问题答案的简单方法,例如“给定一个整数数组,找到满足方程 a^3 + b^3 = c^3 + d^3 的所有组合”

let answer = array.satisfy ({ return pow($0, 3) + pow($1, 3) == pow($2, 3) + pow($3, 3) })

反对更优化的解决方案。

“归还所有 2s”就是

let answer = array.satisfy ({ return $0 == 2 })

单个 for 循环

4

1 回答 1

4

单表达式闭包的参数类型推断的编译器限制/错误

我相信这的根源是编译器中的当前限制(/ bug),使用可变参数推断单行闭包中的参数类型,请参见以下问答

  1. 为什么我不能在带有可变参数匿名参数的单行 Swift 闭包中使用 .reduce()?

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

  1. 内联 if 语句在 void 返回闭包中改变 inout 参数,奇怪的错误(错误:类型“Int1”不符合协议“BooleanType”)

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


当前的解决方法

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

  • 将闭合扩展到单线主体之外

    // ...
    
    [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参数,wrt Q&A 2 中描述的问题。如上链接

    • 它可能已修复,因为bug [SR-7]已解决 (-> Swift 2.2)
    • 然而,似乎是回归 2.2->3.0-dev,wrtinout参数类型推断,如错误报告 [SR-892]中所述。例如,以下代码片段在 Swift 2.2 中有效,但在 3.0-dev 中无效(来自错误报告 [SR-7] 的最小修改的 snipper)

      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 中用于可变参数(this thread and 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,使用运行 Swift 3.0-dev 的 IBM Swift Sandbox进行了测试。

于 2016-04-09T00:10:07.810 回答