Kotlin空检查使用Elvis操作符时{}与()的区别
Kotlin中Elvis操作符场景下
{}与()的语法差异说明 两种写法输出差异的核心原因是:{}和()在Kotlin值表达式位置的语义完全不同,不存在“用花括号包裹表达式分组”的语法规则。
{lastName ?: "No lastName"}的实际语义
在Kotlin语法中,所有出现在值上下文(即需要传入一个具体值的位置,比如字符串拼接的右侧、变量赋值的右侧)的花括号代码块,都是一个无参Lambda表达式,属于函数类型实例,不会自动执行内部代码。
你写的这段花括号代码,实际是定义了一个接收0个参数、返回值为String的函数,对应类型为() -> String,在JVM平台编译后会生成Function0<String>接口的实现类对象。
做字符串拼接时,Kotlin会直接将这个函数对象本身参与拼接,调用对象的toString()方法转成字符串,最终输出Function0<java.lang.String>就是函数对象的默认字符串表现。
如果要拿到花括号内的计算结果,必须在Lambda后面手动加()触发函数调用,即{lastName ?: "No lastName"}(),但这种写法属于无意义的冗余操作,没有实际使用价值。
(lastName ?: "No lastName")的实际语义
Kotlin中的圆括号()才是标准的表达式分组符号,作用是改变运算优先级,括号包裹的整体会被作为单个表达式立刻计算,返回计算结果参与后续运算。
这段代码里,圆括号会保证Elvis操作符?:优先计算:由于lastName值为null,直接返回右侧的默认值"No lastName"字符串,再参与字符串拼接,最终得到预期结果eunno No lastName。
可运行的对比代码
fun main() { var name: String = "eunno" val lastName: String? = null // 错误写法:{}生成Lambda对象,拼接的是函数实例本身 val wrongResult = name + " " + {lastName ?: "No lastName"} println(wrongResult) // 输出:eunno Function0<java.lang.String> // 正确写法:()分组保证Elvis表达式优先计算,返回拼接的字符串值 val correctResult = name + " " + (lastName ?: "No lastName") println(correctResult) // 输出:eunno No lastName // 语法可运行但冗余的写法:手动调用Lambda拿返回值 val redundantResult = name + " " + {lastName ?: "No lastName"}() println(redundantResult) // 输出:eunno No lastName,无实际编码价值 }
关键语法提示
- Kotlin不存在用
{}包裹表达式做分组的语法,不要和其他支持花括号分组的语言混淆,所有需要分组、调整运算优先级的场景统一使用() - Lambda作为函数类型对象,不会隐式自动执行,只有在
()调用、或作为函数参数传入时符合SAM转换/函数类型参数约定的场景下才会被执行 - 字符串拼接的
+运算优先级高于Elvis操作符,如果不在Elvis表达式外加圆括号分组,代码会先执行name + " " + lastName的拼接逻辑,得到非空字符串eunno null,Elvis操作符会因为左侧值非空直接返回左侧结果,不会触发右侧默认值逻辑。
内容的提问来源于stack exchange,提问作者Eunno An
相关产品推荐
相关产品推荐

