Swift可选链接在关闭时不起作用 [英] Swift optional chaining doesn't work in closure
问题描述
我的代码看起来像这样。我的班级有一个可选的var
My code looks like this. My class has an optional var
var currentBottle : BottleLayer?
BottleLayer的方法 jiggle()
。
BottleLayer has a method jiggle()
.
此代码使用可选链接,在我的课程中编译良好:
This code, using optional chaining, compiles fine in my class:
self.currentBottle?.jiggle()
现在我想构造一个使用它的闭包代码:
Now I want to construct a closure that uses that same code:
let clos = {() -> () in self.currentBottle?.jiggle()}
但是我收到编译错误:
找不到会员'jiggle'
Could not find member 'jiggle'
作为一种解决方法,我可以强制展开
As a workaround I can force unwrapping
let clos = {() -> () in self.currentBottle!.jiggle()}
当然我可以使用完整的可选绑定,但我宁愿不。我确实认识到可选链接只是语法糖,但很难理解为什么这种语法糖会因为它处于处理程序中而停止工作(当然,这可能是一个原因 - 但无论如何这都是一个惊喜) 。
or of course I can use full-fledged optional binding, but I'd rather not. I do recognize that optional chaining is just syntactical sugar, but it is hard to see why this syntactical sugar would stop working just because it's in a handler (though there may, of course, be a reason - but it's a surprise in any case).
也许其他人已经闯入这个并对此有所想法?谢谢。
Perhaps someone else has banged into this and has thoughts about it? Thanks.
推荐答案
这不是错误。这只是你的闭包类型错了。
正确的类型应返回一个可选的 Void
以反映可选的链接:
This is NOT a bug. It's simply your closure type which is wrong.
The correct type should return an optional Void
to reflect the optional chaining:
let clos = { ()->()? in currentBottle?.jiggle() }
问题详情:
- 您将闭包声明为一个返回
Void
的闭包(即- >()
)。 - 但是,请记住,就像每次使用可选链接一样,返回类型为整个表达式是的可选类型。因为你的关闭可以返回
Void
如果currentBottle
确实存在... 或nil
如果没有! - You declare your closure as a closure that returns
Void
(namely->()
). - But, do remember that, as like every time you use optional chaining, the return type of the whole expression is of optional type. Because your closure can either return
Void
ifcurrentBottle
do exists… ornil
if it doesn't!
The problem in details:
所以正确的语法是让你的闭包返回 Void?
(或()?
)而不是简单的 Void
So the correct syntax is to make your closure return a Void?
(or ()?
) instead of a simple 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为你推断出正确的类型而不是明确地强迫它,它会为你解决问题:
Note: if you had let Swift infer the correct type for you instead of explicitly forcing it, it would have fixed the issue for you:
// Even better: type automatically inferred as ()->()? — also known as Void->Void?
let clos = { currentBottle?.jiggle() }
你甚至可以将函数直接赋值给变量,如下所示:
You can even assign the function directly to a variable, like so:
let clos2 = currentBottle?.jiggle // no parenthesis, we don't want to call the function, just refer to it
注意<$ c的类型$ c> clos2 (这里没有明确指定,因此由Swift自动推断)在这种情况下不 Void-> Void?
- 即返回 nil
或 Void
)的函数,与前一种情况一样 - 但是是(Void-> Void)?
,这是类型<的可选函数的类型code> Void-> Void 。
Note that the type of clos2
(which is not explicitly specified here and is thus inferred automatically by Swift) in this case is not Void->Void?
— namely a function that returns either nil
or Void
) as in the previous case — but is (Void->Void)?
, which is the type for "an optional function of type Void->Void
".
这意味着 clos2
本身是要么 nil
,要么就是函数n返回无效
。要使用它,您可以再次使用可选链接,就像这样:
This means that clos2
itself is "either nil
or is a function returning Void
". To use it, you could once again use optional chaining, simply like that:
clos2?()
这将评估为 nil
,如果 clos2
本身是 nil
(可能是因为 currentBottle
本身为零)...并执行关闭 - 因此 currentBottle!.jiggle()
代码 - 如果 clos2 <返回
Void
/ code>是非零的(可能是因为 currentBottle
本身是非零的。)
This will evaluate to nil
and do nothing if clos2
is itself nil
(likely because currentBottle
is itself nil)… and execute the closure — thus the currentBottle!.jiggle()
code — and return Void
if clos2
is non-nil (likely because currentBottle
itself is non-nil).
返回类型 clos2?()
本身确实是 Void?
,因为它返回nil或Void。
The return type of clos2?()
itself is indeed Void?
, as it returns either nil or Void.
区分 Void
和 Void?
可能看起来毫无意义(毕竟, jiggle
函数在任何一种情况下都不返回任何内容),但是它可以让你做一些强大的东西,比如测试 Void?
在 if
语句中检查调用是否确实发生(并返回 Void
即没有)或没有发生(并返回 nil
):
Doing the distinction between Void
and Void?
may seem pointless (after all, the jiggle
function does not return anything in either case), but it let you do powerful stuff like testing the Void?
in an if
statement to check if the call actually did happen (and returned Void
namely nothing) or didn't happen (and return nil
):
if clos2?() { println("The jiggle function got called after all!") }
正如你(@matt)指出的那样,这另一种选择还有一个主要区别:它评估表达式受影响的时候> currentBottle?.jiggle
clos2
。因此,如果 currentBottle
当时 nil
, clos2
将是 nil
...即使 currentBottle
稍后获得非零值。
As you (@matt) pointed out yourself, this other alternative has one other major difference: it evaluates currentBottle?.jiggle
at the time that expression got affected to clos2
. So if currentBottle
is nil
at that time, clos2
will be nil
… even if currentBottle
got a non-nil value later.
相反, clos
会对闭包本身产生影响,并且每次 clos
被调用,因此如果 currentBottle
为零,它将评估为 nil
但是将被评估为非零并且将调用 jiggle()
如果我们稍后再调用 clos()
currentBottle
变为非零。
Conversely, clos
is affected to the closure itself, and the optional chaining is only evaluated each time clos
is called, so it will evaluate to nil
if currentBottle
is nil… but will be evaluated to non-nil and will call jiggle()
if we call clos()
at a later time at which point currentBottle
became non-nil.
这篇关于Swift可选链接在关闭时不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!