"Variable expected" 在具有可为空类型的可变映射上调用 getValue 时出错

"Variable expected" error when calling getValue on a mutable map with a nullable type

我在更改可变映射的值时遇到问题。我认为这与可空类型有关,但我不确定。产生错误的代码如下:

fun countHexadecimalNumbers(codes: List<String>): Map<Int, Int> {
  val map = mutableMapOf<Int, Int>()
  for (s in codes) {
    val num = s.toIntOrNull(16)
    if (num != null) {
      if (num !in map.keys) {
        map[num] = 0
      }
      map.getValue(num) += 1 %<--This line causes the issue
    }
  }
  return map

当我尝试构建代码时出现此错误:

Nullable Types\Exercise 3\src\Task.kt: (13, 11): Variable expected

有人知道为什么不允许这样做吗?

语句map.getValue(num) += 1是不允许的,因为+=运算符只在两种情况下定义:

  1. a plusAssign() 运算符是在左操作数的类型上定义的(Int 不是这种情况)
  2. a plus() 运算符定义在左操作数的类型上,并且左操作数是一个 变量 。在这种情况下 += 将左侧的变量重新分配为 oldValue.plus(the right operand).

编译器在这里尝试考虑案例 #2,因为 Int.plus(Int) 已定义,但左操作数不是变量,因此它失败并显示您提到的错误消息。 你不能写这个的原因和你不能写 map.getValue(num) = 42.

的原因一样

改变映射中值的正确方法是通过 set operator (like you did earlier with the syntax sugar map[num] = 0), or via other mutating functions like merge.

在您的情况下,merge 很好,因为它可以完全删除特殊情况(尽管它仅在 JVM 目标上可用):

val map = mutableMapOf<Int, Int>()
for (s in codes) {
    val num = s.toIntOrNull(16)
    if (num != null) {
        map.merge(num, 1, Int::plus)
    }
}

这是 merge 的作用:

  • 如果键不存在于映射中,它只是将给定的值设置为第二个参数(值 1)
  • 如果键已经存在,则使用作为第三个参数给出的函数(只是一个总和)计算一个新值。该函数以旧值和第二个参数(值 1)作为输入调用,并且应该 return 分配新值,所以在这种情况下 old + 1.

请注意,在您的情况下,整个循环可以这样简化:

fun countHexadecimalNumbers(codes: List<String>): Map<Int, Int> {
    return codes.mapNotNull { it.toIntOrNull(16) }.groupingBy { it }.eachCount()
}