You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 07:31:11