我们先建立一个完整且可验证的例子:
precedencegroup LongArrowPrecedence {
associativity: left
higherThan: AssignmentPrecedence
}
infix operator --> : LongArrowPrecedence
func -->(lhs: Int, rhs: Int) -> (() -> ()) -> () {
return { print(lhs+rhs, terminator: ""); $0() }
}
以及使用此运算符的括号括起来的有效调用示例,紧随其后的是对 --> 返回的闭包的调用。
let foo = 1
let bar = 2
// OK
(foo --> bar) {
print(" is the magic number")
} // 3 is the magic number
// OK
((-->)(foo, bar)) {
print(" is the magic number")
} // 3 is the magic number
这并不能告诉我们太多,但如果我们研究以下失败案例
// ERROR: cannot call value of non-function type 'Int'
foo --> bar {
print(" is the magic number")
} // 3 is the magic number
// ... equivalent to
// ERROR: cannot call value of non-function type 'Int'
foo --> bar({
print(" is the magic number")
}) // 3 is the magic number
我们意识到这里的问题不是“优先级低于闭包”,而是function-call-argument-clause(任何后缀表达式后面的一组括号)将尝试一个调用该后缀表达式,就好像后缀表达式是方法/函数/闭包一样。如果后缀表达式不可调用,或者函数调用参数子句中的调用不匹配可调用的任何重载,则编译器将产生错误。
42() // ERROR: cannot call value of non-function type 'Int'
let foo = 42
foo() // ERROR: cannot call value of non-function type 'Int'
func bar() {} // ERROR: argument passed to call that takes no arguments
bar(42)
因此,提供给从 --> 返回的闭包的尾随闭包在这里不相关:它只是返回闭包的一个参数,而关键问题是 Swift 将函数调用参数子句应用于紧接在子句之前的后缀表达式。在您的示例中,bar 构成该后缀表达式,并且仅当您将 foo --> bar 包装在括号中时,组合的包装表达式才会构成应用以下函数调用参数子句的后缀表达式。
后缀表达式
后缀表达式是通过应用后缀运算符或其他
表达式的后缀语法。 从句法上讲,每个主要
表达式也是后缀表达式。
主要表达式
主表达式是最基本的表达式。他们可以
单独用作表达式,并且可以与其他表达式组合使用
用于制作前缀表达式、二进制表达式和后缀的标记
表达式。
您将无法规避这一点,因为运算符优先级不适用于函数调用参数子句;后者(及其“优先级”)由函数调用表达式的语法定义。