swift - 为什么我可以将运算符直接传递给函数,但在其他任何地方都必须用括号括起来?
问题描述
众所周知,您可以将运算符直接传递给如下函数:
func foo(_ x: (Int, Int) -> Int) {
}
foo(+)
但是,当我尝试在分配上下文中执行此操作时,它不起作用:
let f: (Int, Int) -> Int = +
它给出了两个错误:
'=' 后的预期初始值
一元运算符不能与其操作数分开
我发现我必须这样做:
let f: (Int, Int) -> Int = (+)
Swift 究竟是如何解析每一种情况的,允许我在一种情况下省略括号,而在另一种情况下不能?
请注意,我不是在询问以这种方式设计 Swift 背后的基本原理。我只是在询问产生这种行为的语法产生规则。
在 Swift.org 上,我找到了这条生产规则,它说运算符是函数调用参数:
function-call-argument → operator | identifier ':' operator
但是,我无法找到(+)
. 我从“带括号的表达式”开始,这是一对围绕“表达式”的括号。但“算子”显然不是一种“表达”。
解决方案
我找到了Swift AST Explorer,它允许我检查 Swift 代码的 AST。从它的GitHib 页面来看,它似乎使用了 Swift 编译器用来解析 Swift 代码 ( lib/Syntax ) 的同一个库。
使用 Swift AST Explorer,这(+)
部分let x: (Int, Int) -> Int = (+)
解析为:
TupleExpr
(
TupleExprElementList
TupleExprElement
IdentifierExpr
+
)
显然,(+)
这是一个 1 元组!+
并被归类为“标识符表达式” 。这似乎也解释了为什么元组元素中的运算符不需要括号:
let f: ((Int, Int) -> Int, (Bool) -> Bool, (Int) -> Int) = (+, !, -)
经过一番搜索,我找到了 ExprNodes.py,它似乎是生成 lib/Syntax 中的一些 API 的文件之一。在那里,我看到那SpacedBinaryOperatorToken
是 的孩子IdentifierExpr
,所以这可能+
就是被解析的内容。
Node('IdentifierExpr', kind='Expr',
children=[
Child('Identifier', kind='Token',
token_choices=[
'IdentifierToken',
'SelfToken',
'CapitalSelfToken',
'DollarIdentifierToken',
'SpacedBinaryOperatorToken',
]),
Child('DeclNameArguments', kind='DeclNameArguments',
is_optional=True),
]),
有趣的是,一元运算符(例如!
and -
)也被解析为“二元运算符”。
推荐阅读
- php - PHP - 仅在 txt 文件中找到匹配项时追加
- typescript - 反应导航抽屉加倍URI参数
- c - 我的 Makefile 中没有发生链接;返回'未定义的对'main'的引用
- dataweave - Dataweave 2.0 with MaxSize 功能
- python - Pandas 中的数据框拆分问题,有什么想法吗?
- java - Java HashSet 最坏情况查找时间复杂度
- python - python请求发出429错误请求
- c - CS50 恢复 - 我如何使用 sprintf?错误:使用未声明的标识符“文件名”;您指的是 'rename' 吗?
- html - 如何在此设置中换行后使嵌套的 css flex 具有正确的宽度?
- reactjs - 打字稿中的 useState 和 React.FC 问题