如何在swift中使用可变闭包? [英] How to use a variadic closure in 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
也出现在Swift 2.1中的 inout
参数中(但不再在2.2中),如以下线程中解释的
< ol begin =2>
查看线程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){}
pre>
let g = {x in f(& x)} // OK 2.2,crash 3.0-dev
-
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
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
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 toInt
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屋!