Kotlin编译器如何判断{}包裹的表达式是代码块还是lambda?
Kotlin中{}被解析为代码块还是lambda的判断规则
Kotlin编译器对{}的解析遵循3条优先级从高到低的规则:
- 规则1:存在显式lambda参数声明的
{},直接判定为lambda
只要{}内开头带有->格式的参数声明(比如{ x -> x + 1 }、{ -> 1 }),不管所处位置是什么,都会被识别为lambda表达式。 - 规则2:处于语法强制要求语句块位置的
{},直接判定为代码块
以下位置的{}会被优先识别为代码块:- 函数、类、接口、对象的主体定义位置,比如
fun test() { ... } - if/for/while/do-while/try/catch等流程控制结构的分支体位置,比如
if (a > 0) { ... }中紧跟条件后的{}
- 函数、类、接口、对象的主体定义位置,比如
- 规则3:不属于上述两种情况时,通过上下文预期类型判断
- 如果当前位置的预期类型是函数类型(比如
() -> Int),{}被解析为对应类型的lambda - 如果当前位置的预期类型不是函数类型,
{}被解析为代码块,代码块的返回值为块内最后一行表达式的结果
- 如果当前位置的预期类型是函数类型(比如
示例解释
你遇到的差异完全符合上述规则:
// 写法1:a显式声明为() -> Int类型 val a: () -> Int if (cond) a = { 1 } // 赋值运算符右侧预期类型是() -> Int,走规则3判定为lambda else a = { 2 }
// 写法2:a无显式类型声明,由编译器推断 val a = if (cond) { 1 } // 处于if分支体位置,走规则2优先判定为代码块,返回值为Int else { 2 } // 最终a的推断类型为Int,和lambda无关
如果需要在无显式变量类型声明的场景下让{}被识别为lambda,只需要主动给{}增加预期类型提示即可:
val a = if (cond) { 1 } as () -> Int else { 2 } as () -> Int
内容的提问来源于stack exchange,提问作者k314159
相关产品推荐
相关产品推荐

