函数被调用但不执行

时间:2017-07-21 07:42:33

标签: swift closures custom-operator

我有这个自定义运算符:

infix operator ?> : NilCoalescingPrecedence
func ?> (lhs: Any?, rhs: @autoclosure ()->Any) {
    if lhs == nil {
        print("lhs is nil")
        rhs()
    }
}

用法:

optional ?> {
    print("executing")
}

问题是,当lhs为nil时,闭包没有执行。在控制台" lhs是零"正在打印,但没有"正在执行"正在打印。如何" lhs是零" print语句已执行但不是rhs

4 个答案:

答案 0 :(得分:2)

导致此行为的原因是@autoclosure,如果删除它,则可以正常工作。

这是因为@autoclosure会将你的闭包包装成一个闭包,所以现在你有这样的东西:

{ { print("executing") } }

外部封闭返回Any,对吗?所以它只会返回闭包{ print("executing") }而不做任何其他事情。

如果您想保留@autoclosure,可以这样使用运营商:

optional ?> print("executing")

答案 1 :(得分:1)

解决方案似乎是为操作符添加了一个具有完全相同签名的重载,除了它没有@autoclosure注释,并且两者的rhs必须返回Void代替Any

infix operator ?> : NilCoalescingPrecedence
func ?> (lhs: Any?, rhs: @autoclosure ()->Void) {
    if lhs == nil {
        print("lhs is nil")
        rhs()
    }
}
func ?> (lhs: Any?, rhs: ()->Void) {
    if lhs == nil {
        print("lhs is nil")
        rhs()
    }
}

如果我这样做:

optional ?> doSomething()
无论@autoclosure是否返回任何内容,

doSomething()都会被调用。

如果我这样做:

optional ?> {
    doSomething()
    doSomethingElse()
}

将调用没有@autoclosure的那个,因为闭包的类型为()->Void

答案 2 :(得分:0)

您需要在闭包方法的末尾添加(),如下所示

optional ?> {
    print("executing")
}()

答案 3 :(得分:0)

如果您打算在运算符之后添加花括号 ,则可以实现它(无需将rhs声明为autoclosure):

infix operator ?> : NilCoalescingPrecedence

func ?> (lhs: Any?, rhs: ()->Any) {
    if lhs == nil {
        print("lhs is nil")
        rhs()
    }
}

var myString: String? = ""

// some case that made "string" to be nil...
myString = nil

myString ?> {
    print("executing")
}

然而,声明autoclosure的目的是包装一个作为参数传递给函数的表达式:

  

这种语法上的便利性可以省略函数的大括号   通过编写普通表达式而不是显式来创建参数   闭合。

     

The Official Swift Documentation - Closures,Autoclosures

这意味着不需要花括号,在使用操作符时应该更自然:

infix operator ?> : NilCoalescingPrecedence

func ?> (lhs: Any?, rhs: @autoclosure ()->Any) {
    if lhs == nil {
        print("lhs is nil")
        rhs()
    }
}

 var myString: String? = ""

 // some case that made "string" to be nil...
 myString = nil

// you could use your operator like:
 myString ?> print("executing")

但等等!

可能会遇到一个问题:如果应该在运营商之后添加一大堆代码怎么办?

嗯,毫无疑问你必须添加大括号:

let doSomething = {
    print("executing")
    print("second line of execution")
    print("third line of execution")
}

myString ?> doSomething()