如何在swift中使用可变闭包? [英] How to use a variadic closure in swift?

查看:198
本文介绍了如何在swift中使用可变闭包?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



在swift中我注意到我可以声明一个函数接受一个可变参数列表像这样

 协议NumberType:Comparable,IntegerLiteralConvertible,IntegerArithmeticType {} 
extension Int:NumberType {}

extension SequenceType where Generator.Element:NumberType {
func satisfied(closure:(args:Generator.Element ...) - >()){
//做某事
closure(args:1,2,3)
}
}

其中构建正好。当我尝试使用函数:

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

Xcode可以自动完成,括号后的所有语法高亮显示在Xcode消失,我看到一个消息命令失败,由于信号:分段故障:11,这似乎只是意味着Xcode是超级困惑。



对于上下文,我计划看看Swift是否可以写一个函数,它可以返回基于可变数量参数的答案(映射到for循环的数量需要得到一个强力答案)。这将是一种测试对诸如给定Ints数组,找到满足等式a ^ 3 + b ^ 3 = c ^ 3 + d ^ 3的所有组合的问题的答案的简单方式,其中

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


$ b

返回所有的2s只是

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

单个for循环

解决方案

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



编译器wrt中的当前限制(/ bug)使用可变参数来推断单线闭包中的参数类型,参见例如。以下Q& A


  1. 为什么我在一个具有可变参数,匿名参数的单行Swift闭包中使用.reduce()?

也出现在Swift 2.1中的 inout 参数中(但不再在2.2中),如以下线程中解释的



< ol begin =2>
  • Inline if语句在void返回闭包中抛出inout参数,奇怪的错误(错误:类型Int1不符合协议'BooleanType')

  • 查看线程1.以及尝试找到在 Swift JIRA 中标记的描述的错误,但是,看起来好像OP的线程1。从来没有提出这个问题,毕竟。可能我只是没有找到一个现有的错误报告,但如果没有存在,应该可以提交。






    解决方法



    可能的解决方法,直到编译器的闭包参数类型推断出现,




    • 延长关闭超出单行正文

        // ... 

      [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



    $ b

    $ b


    Swift 3.0-dev的当前状态



    如上所述,奇怪的是, p>


    • inout:显然不再出现在Swift 2.2或Swift 3.0-dev中, inout arguments,wrt 与上述链接的问答&A 2.描述的问题




      • 这可能会修正为错误[SR-7] ( - > Swift 2.2)

      • 但是,似乎是回归2.2-> 3.0-dev,wrt类型推断 inout 参数,如错误报告[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,crash 3.0-dev
        pre>


    • variadic: 3.0-dev用于可变参数(此主题和上述问答)。




      • 一个更为精简的错误示例:

          :(Int ...) - > ()= {(args)in print(args)} //错误:崩溃
        let b:(Int ...) - > ()= {(args:Int ...)in print(args)} //显式状态参数类型,OK
        let c:(Int ...) - > ()= {(args)in(); print(args)} //扩展到多行闭包,OK





    (对于Swift 3.0-dev,使用 IBM Swift Sandbox运行Swift 3.0-dev


    Is there a proper way to use a variadic parameter list in a closure in Swift?

    In swift I notice that I can declare a function which takes a variadic argument list like so

    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)
        }
    }
    

    Which builds just fine. When I try to use the function:

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

    Xcode manages to auto complete as I would expect, but immediately upon closing the parenthesis after args, all syntax highlighting in Xcode disappears and I see a message "Command failed due to signal: Segmentation Fault: 11", which appears to just mean Xcode is super confused.

    For context, I had planned on seeing if Swift could write a function which could return answers based on a variable number of parameters (mapping to the number of for loops required to get a brute force answer). It would be a simple way of testing the answer to a question such as "Given an array of Ints, find all combinations which satisfy the equation a^3 + b^3 = c^3 + d^3" with

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

    against a more optimal solution.

    "Return all the 2s" would just be

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

    A single for loop

    解决方案

    Compiler limitation/bug with argument type inference for single-expression closures

    I believe the source of this is a current limitation (/bug) in the compiler w.r.t. inferring the argument types in single-line closures using variadic parameters, see e.g. the following Q&A

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

    A similar issue was also present for inout arguments in Swift 2.1 (but no longer in 2.2), as is explained in the following thread

    1. Inline if statement mutating inout parameter in a void return closure, weird error (Error: type 'Int1' does not conform to protocol 'BooleanType')

    Looking at thread 1. as well as attempting to find the described bug flagged in Swift JIRA, however, it seems as if the OP of thread 1. never filed a bug for this, after all. Possibly I just haven't found an existing bug report, but if none exists, one should possibly be filed.


    Current workarounds

    Possible workarounds, until the compiler's closure argument type inference catches up, are

    • Extend the closure beyond single-line body

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

    • Or, explicitly include type of args, e.g.

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

      Note that Generator.Element resolves to Int in this example above.


    Current status for Swift 3.0-dev

    As mentioned briefly above, curiously enough, this bug

    • inout: is apparently no longer present in Swift 2.2 or Swift 3.0-dev for inout arguments, w.r.t. the issues described in Q&A 2. as linked to above

      • it was possibly fixed as bug [SR-7] was resolved (-> Swift 2.2)
      • however, seems to be regression 2.2->3.0-dev, w.r.t. type inference for inout arguments, as reported in bug report [SR-892]. E.g. the following snippet works in Swift 2.2, but not in 3.0-dev (minimally modified snipper from bug report [SR-7])

        func f(inout a: Int) {}
        let g = { x in f(&x) }  // OK 2.2, crashes 3.0-dev
        

    • variadic: is still present in Swift 2.2 as well as Swift 3.0-dev for variadic arguments (this thread and Q&A 1. above).

      • a more condensed example of the bug:

        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
        

    (For Swift 3.0-dev, tested using the IBM Swift Sandbox running Swift 3.0-dev.

    这篇关于如何在swift中使用可变闭包?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆