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

为何Kotlin允许非空值声明为可空类型却仍按非空处理?

Kotlin中为何允许将非空Map的值声明为可空类型后直接传给非空参数?

先看你给出的代码:

class WorkoutHistory(
    history: Map<Workout, Int> = EnumMap(Workout::class.java)
) {

    private val history: EnumMap<Workout, Int> = EnumMap(history)

    init {
        history.forEach { (workout: Workout, reps: Int?) ->
            doSomething(workout, reps)
        }
    }

    private fun doSomething(workout: Workout, reps: Int) {
        // Do something
    }
}

这是Kotlin编译器的有意设计,并非疏漏,原因可以拆解为两点:

  • 参数类型的向上兼容:Map<Workout, Int>的forEach方法接收的lambda参数类型是(Workout, Int) -> Unit,但Kotlin允许你给lambda里的参数声明更宽泛的类型(这里把Int声明为Int?)。因为非空类型Int是可空类型Int?的子类型,这种向上转型是完全安全的,编译器不会阻止你这么做。

  • 智能类型推断的作用:虽然你把reps声明成了Int?,但编译器能通过上下文判断出实际值的非空性——原始的history是EnumMap<Workout, Int>,其中存储的所有值都是非空的Int,所以遍历出来的reps不可能为null。基于这个推断,编译器允许你直接把reps传给要求非空Int参数的doSomething函数,不会触发空安全检查报错。

你可以做个测试:如果把构造函数的history参数改成Map<Workout, Int?>,这时候编译器就会立刻报错,提示你reps可能为null,必须做非空处理(比如用reps!!或者reps?.let{...})。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 20:02:37