作为对Ruby的致敬,我一直在使用Int的扩展,允许我编写这样有用的代码:
3.times { println("I keep holding on") }
这很好用,这是扩展名:
extension Int {
func times(fn: () -> ()) {
for i in 1...self {
fn()
}
}
}
现在,我想将迭代号传递给闭包,所以我在扩展中添加了第二次()函数:
extension Int {
func times(fn: (iteration: Int) -> ()) {
for i in 1...self {
fn(iteration: i)
}
}
}
可以这样调用:
5.times { (i: Int) -> () in println("Year \(i)") }
现在,根据Swift文档,
始终可以推断参数类型和返回类型 将闭包传递给函数作为内联闭包表达式时。 因此,您永远不需要完整地编写内联闭包 当闭包使用函数参数时形成。
听起来不错,因为我可以省略参数和返回类型,即(i: Int) -> ()
,只需使用以下语法:
5.times { i in println("Year \(i)") }
但是这会导致以下错误:Error: Ambiguous use of 'times'
这种方式是调用我的times()
函数真的对编译器不明显吗?
答案 0 :(得分:3)
这是模棱两可的。如果闭包的参数类型未知,则.times()
方法都可以与给定的闭包表达式一起使用。
如果你只是写{ i in println("Year \(i)") }
,它只是一个闭包,它接受任何类型的一个参数。好吧,Swift中的每个函数类型都可以看作是一个参数:
()
类型的一个参数(又名Void
),值为()
,这就是为什么类型被写为{{1 }} () -> something
。因此,基本上,您的闭包表达式(不指定(foo, bar) -> something
的类型)可以推断为返回i
的Swift中的任何函数类型。两个Void
方法采用的函数都匹配 - 对于第一个.times()
方法,它被推断为类型.times()
的函数,即() -> ()
具有类型{{1 }};对于第二个i
方法,它被推断为类型()
的函数,即.times()
具有类型Int -> ()
。
答案 1 :(得分:2)
看起来模糊性来自具有相同名称的2种扩展方法。如果您对times
函数的第一个版本发表评论,它可以正常工作 - 如果您对第二个版本进行评论,那么,令人惊讶的是,不会从编译器中获取错误。
我认为没有歧义,因为2个函数具有不同的签名 - () -> ()
与(iteration: Int) -> ()
不同。我认为它是编译器中的一个错误,特别是类型推断失败。
使呼叫显式而不是正常
5.times { (i: Int) -> () in println("Year \(i)") }
如果注释了无参数闭包的第一个版本,则上面的行正确编译,如果第二个重载被注释,则编译按预期失败。
为了证明编译器出了问题,这似乎有效,而我反对编译错误:
extension Int {
func times(fn: () -> ()) {
for i in 1...self {
fn()
}
}
}
5.times { i in println("Year \(i)") }
这是游乐场控制台的输出:
Year ()
Year ()
Year ()
Year ()
Year ()