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

Kotlin空检查编译器契约如何工作?自定义applyIf如何透传非空断言?

核心问题原因

你原来的实现中condition是固定Boolean类型的入参,Kotlin编译器无法跟踪这个布尔值对应的判断逻辑(比如source != null)和后续block执行的关联关系,因此空检查的智能转换信息无法穿透函数边界传递到block内部。

优化实现方案

你需要将参数改为函数类型的条件判断,同时结合Kotlin契约保证调用规则,即可让编译器正确识别条件判断的状态,实现预期的智能转换效果。以下提供两种常用重载实现,覆盖不同使用场景:


1. 通用条件判断版本

适用于所有自定义条件判断场景,支持针对接收器自身或外部变量的条件校验:

@OptIn(ExperimentalContracts::class)
inline fun <R> R.applyIf(condition: () -> Boolean, block: R.() -> Unit): R {
    contract {
        // 保证condition只会被执行一次
        callsInPlace(condition, InvocationKind.EXACTLY_ONCE)
        // 保证block最多只会被执行一次
        callsInPlace(block, InvocationKind.AT_MOST_ONCE)
    }
    if (condition()) block()
    return this
}

使用示例

.applyIf({ source != null }) {
    // 此时编译器可以正确识别source已非空,不会触发告警
    sourceClassName = source.className
    sourceMethodName = source.methodName
}

2. 非空判断专用版本

针对最常用的非空校验场景做专门优化,使用更简洁,无需额外写判断表达式:

@OptIn(ExperimentalContracts::class)
inline fun <R, T> R.applyIfNotNull(value: T?, block: R.(T) -> Unit): R {
    contract {
        callsInPlace(block, InvocationKind.AT_MOST_ONCE)
    }
    value?.let { block(it) }
    return this
}

使用示例

.applyIfNotNull(source) { nonNullSource ->
    // 直接拿到非空的source实例,无需额外空判断
    sourceClassName = nonNullSource.className
    sourceMethodName = nonNullSource.methodName
}
实现原理

将静态布尔值入参改为函数类型的条件后,条件判断逻辑会在applyIf函数内部执行,结合契约对调用次数的明确保证,Kotlin编译器可以正确推导:当block被执行时,condition的返回值一定为true,因此条件中包含的空检查、类型检查等状态都会被正确透传到block内部,实现和原生if判断一致的智能转换效果。

内容的提问来源于stack exchange,提问作者neph

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 03:39:02