我的代码看起来像这样。我的班级有一个可选的var
var currentBottle : BottleLayer?
BottleLayer有一个方法jiggle()
。
这段代码使用可选链接,在我的课程中编译得很好:
self.currentBottle?.jiggle()
现在我想构造一个使用相同代码的闭包:
let clos = {() -> () in self.currentBottle?.jiggle()}
但是我收到编译错误:
找不到会员' jiggle'
作为一种解决方法,我可以强制解包
let clos = {() -> () in self.currentBottle!.jiggle()}
当然我可以使用完整的可选绑定,但我不愿意。我确实认识到可选链接只是语法糖,但很难理解为什么这种语法糖会因为它处理器而停止工作(当然,这可能是一个原因 - 但它&#39 ;无论如何都是惊喜。)
也许其他人已经闯入这个并对此有所想法?感谢。
答案 0 :(得分:19)
这不是一个错误。它只是你的闭包类型是错误的。
正确的类型应返回可选的Void
以反映可选的链接:
let clos = { ()->()? in currentBottle?.jiggle() }
Void
的闭包(即->()
)。Void
确实存在,可以返回currentBottle
... 或nil
,如果它不存在!所以正确的语法是让你的闭包返回Void?
(或()?
)而不是简单的Void
class BottleLayer {
func jiggle() { println("Jiggle Jiggle") }
}
var currentBottle: BottleLayer?
currentBottle?.jiggle() // OK
let clos = { Void->Void? in currentBottle?.jiggle() } // Also OK
let clos = { () -> ()? in currentBottle?.jiggle() } // Still OK (Void and () are synonyms)
注意:如果您让Swift为您推断出正确的类型而不是明确强制它,那么它可以解决您的问题:
// Even better: type automatically inferred as ()->()? — also known as Void->Void?
let clos = { currentBottle?.jiggle() }
[编辑]
您甚至可以将函数直接分配给变量,如下所示:
let clos2 = currentBottle?.jiggle // no parenthesis, we don't want to call the function, just refer to it
请注意,clos2
的类型(此处未明确指定,因此由Swift自动推断)在这种情况下不 Void->Void?
- 即一个函数返回nil
或Void
),与前一种情况相同 - 但为(Void->Void)?
,这是&#34; 可选<的类型/ strong>类型Void->Void
的功能&#34;。
这意味着clos2
本身就是&#34; nil
或者是返回Void
&#34;的函数。要使用它,您可以再次使用可选链接,就像这样:
clos2?()
这将评估为nil
,如果clos2
本身为nil
,则不执行任何操作(可能因为currentBottle
本身为零)...并执行闭包 - 因此{{ 1}}代码 - 如果currentBottle!.jiggle()
非零,则返回Void
(可能因为clos2
本身不为零)。
currentBottle
本身的返回类型确实是clos2?()
,因为它返回nil或Void。
区分Void?
和Void
可能看起来毫无意义(毕竟,Void?
函数在任何一种情况下都不会返回任何内容),但它可以让你做一些强大的事情,比如测试jiggle
语句中的Void?
来检查调用是否确实发生(并且返回if
即没有)或者没有发生(并且返回Void
):
nil
[EDIT2]正如您(@matt)指出的那样,另一个替代方案还有另一个主要区别:它在表达式受if clos2?() { println("The jiggle function got called after all!") }
影响时评估currentBottle?.jiggle
。因此,如果当时clos2
为currentBottle
,则nil
将为clos2
...即使nil
稍后获得非零值。
相反,currentBottle
会对闭包本身产生影响,并且每次调用clos
时都会评估可选链接,因此如果clos
它将评估为nil
是零......但如果我们稍后调用currentBottle
jiggle()
变为非零,则会被评估为非零,并且会调用clos()
。
答案 1 :(得分:7)
let closure = { () -> () in
self.currentBottle?.jiggle()
return
}
否则编译器认为应该从闭包返回该语句的结果,并且它意识到()
(返回类型)与语句(Optional<Void>
)返回的可选项之间存在不匹配。通过添加显式return
,编译器将知道我们不想返回任何内容。
错误信息当然是错误的。
答案 2 :(得分:1)
好的,另一种方法。这是因为Swift中的闭包具有单表达式闭包的隐式返回。由于可选链,您的闭包的返回类型为Void?
,因此:
let clos = {() -> Void? in self.currentBottle?.jiggle()}
答案 3 :(得分:0)
让推断闭包类型似乎也有效。
let clos2 = { currentBottle?.jiggle() }
clos2() // does a jiggle
但我很确定这只是编译器分配() -> ()?