Kotlin中可为空变量分两个逻辑块赋值的惯用写法咨询
如何实现符合优先级的可为空参数查询逻辑?
我的需求是:
- 先判断参数
a是否非空,若a非空则执行aCollection.firstOrNull{it.foo == a}(无论返回结果是否为null,都用这个结果) - 只有当
a为空时,才判断参数b是否非空,再执行aCollection.firstOrNull{it.bar == b}
但当前代码中,当a非空但查询结果为null时,会进入Elvis运算符后的run块执行b的查询,不符合预期:
fun foo( a: Int?, b: Int?, aCollection: List<FooBar> ): FooBar?{ val result = a?.let{ aCollection.firstOrNull{it.foo == a}// 这里返回null时,会触发?:后的逻辑,不是我想要的 }?: run{ b?.let{ aCollection.firstOrNull{it.bar == b} } } return result }
问题根源
a?.let{...}的逻辑是:当a非空时执行lambda,lambda的返回值就是整个表达式的结果。如果lambda返回null,那么整个a?.let{...}的结果就是null,这会触发Elvis运算符?:执行右侧代码——但我们的需求是仅当a本身为空时才走b的逻辑,和a对应的查询结果是否为null无关。
正确实现方式
方式一:使用if-else(最直观)
直接通过a的非空性判断分支,完全符合需求逻辑:
fun foo( a: Int?, b: Int?, aCollection: List<FooBar> ): FooBar? { return if (a != null) { aCollection.firstOrNull { it.foo == a } } else { b?.let { aCollection.firstOrNull { item -> item.bar == b } } } }
方式二:使用when表达式(更简洁)
利用when的优先级判断特性,代码可读性更高:
fun foo( a: Int?, b: Int?, aCollection: List<FooBar> ): FooBar? { return when { a != null -> aCollection.firstOrNull { it.foo == a } b != null -> aCollection.firstOrNull { it.bar == b } else -> null } }
方式三:拆分逻辑(保留let的写法)
如果想继续使用let,可以先获取a的查询结果,再通过a的非空性决定返回值:
fun foo( a: Int?, b: Int?, aCollection: List<FooBar> ): FooBar? { val resultFromA = a?.let { aCollection.firstOrNull { item -> item.foo == a } } return resultFromA.takeIf { a != null } ?: b?.let { aCollection.firstOrNull { item -> item.bar == b } } }
这些实现都能保证:只要a非空,就只会返回针对a的查询结果(无论是否为null),只有a为空时才会处理b的逻辑。
内容的提问来源于stack exchange,提问作者Pipo
相关产品推荐
相关产品推荐

