相关文章推荐
喝醉的卤蛋  ·  SQL Server ...·  2 周前    · 
强健的猕猴桃  ·  NumberStyles 枚举 ...·  1 周前    · 
旅行中的胡萝卜  ·  C# ...·  1 年前    · 
机灵的手电筒  ·  Oops!!! - 简书·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I'm having a problem with altering the value of a mutable map. I assume it's something to do with nullable types, but I'm not sure. The code producing the error is below:

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

When I try and build the code I get this error:

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

Does anyone have any idea why this isn't allowed?

The statement map.getValue(num) += 1 is not allowed because the += operator is only defined in 2 cases:

  • a plusAssign() operator is defined on the left operand's type (not the case for Int)
  • a plus() operator is defined on the left operand's type AND the left operand is a variable. In this case += reassigns the variable on the left with oldValue.plus(the right operand).
  • The compiler tries to consider case #2 here because Int.plus(Int) is defined, but the left operand is not a variable so it fails with the error message you mentioned. You can't write this for the same reasons you can't write map.getValue(num) = 42.

    The correct way of mutating a value in a map is either via the set operator (like you did earlier with the syntax sugar map[num] = 0), or via other mutating functions like merge.

    In your case, merge is nice because it can remove the special case altogether (it's only available on the JVM target though):

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

    Here is what this merge does:

  • if the key doesn't exist in the map, it just sets the value given as second argument (the value 1)
  • if the key already exists, then a new value is computed using the function given as 3rd argument (just a sum). That function is called with the old value and the 2nd argument (the value 1) as inputs, and should return the new value to assign, so in this case old + 1.
  • Note that, in your case, the whole loop can be simplified this way:

    fun countHexadecimalNumbers(codes: List<String>): Map<Int, Int> {
        return codes.mapNotNull { it.toIntOrNull(16) }.groupingBy { it }.eachCount()
                    So when I call getValue, what exactly is returned? I assumed it was a reference to the data in the map.
    – Connor
                    Jun 15, 2021 at 13:11
                    @Connor it returns the value associated with the key. If this value is of a primitive type, you cannot change it. If the value is a reference type, you cannot change the reference either (so you can't change which object the key is associated to), but you can change the contents of the object if it has mutable fields. You can draw a parallel with function parameters: you can do as much to getValue's result as what you can do to function parameters from inside a function's body.
    – Joffrey
                    Jun 15, 2021 at 13:52
            

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.