Kotlin编译器如何决定{
}
中包含的表达式是块还是lambda?
考虑一下:
val a: Int
if (cond)
a = 1
else
a = 2
可以更简洁地写成:
val a =
if (cond)
1
else
2
类似地,有人可能会认为:
val a: () -> Int
if (cond)
a = { 1 }
else
a = { 2 }
应该可以写得更简洁,像这样:
val a =
if (cond)
{ 1 }
else
{ 2 }
但这是不一样的:a
现在是Int
,而不是() -> Int
类型,因为现在{ 1 }
不再是一个lambda。是什么规则决定一个是还是一个块?
我没有研究Kotlin词法分析器,但是我猜想在代码中很少有编译器期望单个表达式或代码块的地方。这包括紧跟在大多数控制流语句后面的代码,如:if
,else
,while
,when
(其中一种情况)等。如果您将{
放在这些位置之一,它将被解释为与此控制流语句相关的代码块的开始,而不是作为lambda。
就是这么简单。请注意,即使您提示编译器类型,它仍然不会工作:
// compile error
val a: () -> Int = if (cond)
{ 1 }
else
{ 2 }
可以这样解释:
// compile error
val a: () -> Int = if (cond) {
1
} else {
2
}
if
条件之后的{
总是被解释为代码块的开始。你需要在这样的情况下添加双{
,}
:
// works fine
val a: () -> Int = if (cond) {
{ 1 }
} else {
{ 2 }
}
简单地说,if/when/else/for后面的第一个左括号总是被认为是一个块的开始。如果你想要一个lambda,请使用双括号。
这在Kotlin语言规范第1.2节:语法语法:
中指定语法将块定义为{
和}
之间的语句。在大多数情况下(比如函数体),块和lambda的语法是不同的。在controlStructureBody的使用中是相同的-这些是块具有值的地方,或者您可以在其位置放置非块表达式。如果您在整个规范文档中搜索"controlStructureBody",您会发现它在以下地方使用:
- <
- 而声明/gh><
- 延伸的声明/gh><
- 如果表达式/gh><
- 当表达式/gh><
- 当条目/gh>
在其他需要值的地方,'{'表示lambda的开始。