在Kotlin中,从map访问值会以不同的方式提供不同的接收器类型

映射的类型为LinkedHashMap类型

如果我不在此行中为空判断

println("Morning: ${daypartEvents[Daypart.MORNING].size}")

编译器给出了错误

List类型的可空接收器上只允许安全(?.)或非空的断言(!!.)调用.

但是,如果try 通过使用forEach函数迭代映射来实现相同的结果,则如下所示

daypartEvents.forEach { (daypart, events) -> println("$daypart: ${events.size}") }

它不想让我对它进行空判断.

即使我做了空判断,它也会说

对List类型的非null接收器进行不必要的安全调用

我知道这个问题表达得很糟糕,所以请原谅我

这里我想知道的是,为什么List类型的映射值一开始是可以为空的,之后是不可为空的.

为清晰起见,完整代码

enum class Daypart {
    MORNING, AFTERNOON, EVENING
}

data class Event (
    val title: String,
    val description: String? = null,
    val daypart: Daypart,
    val duration: Int
)

fun main() {
    
    val event1 = Event(title = "Wake up", description = "Time to get up", daypart = Daypart.MORNING, duration = 0)
    val event2 = Event(title = "Eat breakfast", daypart = Daypart.MORNING, duration = 15)
    val event3 = Event(title = "Learn about Kotlin", daypart = Daypart.AFTERNOON, duration = 30)
    val event4 = Event(title = "Practice Compose", daypart = Daypart.AFTERNOON, duration = 60)
    val event5 = Event(title = "Watch latest DevBytes video", daypart = Daypart.AFTERNOON, duration = 10)
    val event6 = Event(title = "Check out latest Android Jetpack library", daypart = Daypart.EVENING, duration = 45)
    
    val events = mutableListOf<Event>(event1, event2, event3, event4, event5, event6)
    
    
    val daypartEvents = events.groupBy {
        it.daypart
    }
    
    print(daypartEvents::class.simpleName)
    
    
    println("Morning: ${daypartEvents[Daypart.MORNING]?.size}")
    
    daypartEvents.forEach { (daypart, events) ->
        println("$daypart: ${events.size}")
    }
    
}

我对Kotlin还是个新手,这是Developer.android.com上Android Jetpack Compose for Beginners课程中的练习之一

推荐答案

一般而言,映射可能有也可能没有特定的键.因此,即使值的类型不可为空,如果键不在映射中,通过键访问值的表达式也可能返回空.编译器对代码的分析不够深入,无法理解在您的特定情况下,键Daypart.MORNING将始终在那里.

这就是为什么在第一种情况下,daypartEvents[Daypart.MORNING]是可以为空的.

第二个 case 不同.您不是在try 访问 map 中的特定密钥.您对映射中当前实际存在的所有映射(条目)进行迭代.对于那些,我们知道它们的值不能为空,因此不需要进行空判断.

回到第一种情况,您还可以 Select 在密钥不存在的情况下获取异常(失败)而不是NULL.这是通过使用daypartEvents.getValue(Daypart.MORNING)而不是方括号语法as pointed out by @JSmonk来实现的.错误消息将指出哪个键不在映射中.当您确定它们的关键字将始终在映射中时,或者如果您无论如何都要失败,并且此错误适合您,则此功能非常有用.

Kotlin相关问答推荐

我可以检测一个函数是否在Kotlin中被递归调用(即,重入)吗?

Kotlin 说不需要强制转换,但删除后会出现新警告

为什么Kotlin有次构造函数和init块?

Kotlin supervisorScope 即使包裹在 try catch 中也会失败

如何将光标从一个文本字段传递到 Jetpack Compose 中的其他文本字段?

有什么方法可以要求在 kotlin 中的类型参数上进行注释?

Kotlin 中获取类简单名称的最佳实践

为什么没有remember 的 mutableStateOf 有时会起作用?

如何退出 Kotlinc 命令行编译器

Foo::class.java 和 Foo::javaClass 有什么区别?

Kotlin 单元测试 - 如何模拟 Companion 对象的组件?

带有迭代器函数的 Kotlin 无限序列

如何在MVVM架构中观察RecyclerView适配器中的LiveData?

类型不匹配:推断类型为 LoginActivity 但应为 LifecycleOwner

在Kotlin中将列表转换为对的惯用方法

Kotlin 的数据类 == C# 的 struct ?

你如何在 Kotlin 中注释 Pair 参数?

Kotlin:测试中的 java.lang.NoSuchMethodError

项目不会使用 Kotlin 1.1.3 构建

如何在 Kotlin 中按字母顺序对字符串进行排序