1

我有这个自定义运算符:

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

用法:

optional ?> {
    print("executing")
}

问题是,当lhs为 nil 时,闭包没有执行。在控制台中“lhs is nil”正在打印,但之后没有“执行”正在打印。如何执行“lhs is nil”打印语句但不执行rhs

4

4 回答 4

2

导致这种行为的原因是@autoclosure,如果你删除它,它工作正常。

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

{ { print("executing") } }

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

如果要保留@autoclosure,可以这样使用运算符:

optional ?> print("executing")
于 2017-07-21T07:55:24.080 回答
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将调用的那个,因为闭包是 type ()->Void

于 2017-07-21T23:37:39.673 回答
0

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

optional ?> {
    print("executing")
}()
于 2017-07-21T07:50:29.757 回答
0

如果您的意图是必须在运算符之后添加花括号,则可以将其实现(无需声明rhs为自动关闭):

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")
}

但是,声明自动关闭的目的是包装作为参数传递给函数的表达式:

这种语法便利让您可以通过编写普通表达式而不是显式闭包来省略函数参数周围的大括号。

官方 Swift 文档 - 闭包,自动闭包

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

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()
于 2017-07-21T08:00:55.877 回答