Kotlin: Modifying (immutable) List through cast, i

2019-04-28 19:28发布

问题:

As we know the List in Kotlin is immutable i.e. you can't do add and remove as below.

class TempClass {
    var myList: List<Int>? = null
    fun doSomething() {
        myList = ArrayList<Int>()
        myList!!.add(10)
        myList!!.remove(10)
    }
}

But if we cast it to ArrayList as below, the add and remove works.

class TempClass {
    var myList: List<Int>? = null
    fun doSomething() {
        myList = ArrayList<Int>()
        (myList!! as ArrayList).add(10)
        (myList!! as ArrayList).remove(10)
    }
}

I just thought this is odd, as myList is really a List, which is suppose to be immutable. And casting it, allow it to be altered.

Is what done above (casting to Array and modify the content) legitimate, or the language need to improve to disallow that?

回答1:

There are a few different types of immutability:

One is mentioned from a separate SO answer here.

Readonly - you are NOT supposed to change it (Kotlin's List) but something may (cast to Mutable, or change from Java).

List is just an interface that does not have mutating methods, but you can change the instance if you cast it to MutableList.

Someone then goes on to comment that Kotlin chose to be readonly in order to use Java collections directly, so there is no overhead or conversion in using Java collections.

Kotlin List is readonly, not immutable. Other callers (Java for example) may change the list. Kotlin callers might cast the list and change it. There is no immutable protection.

Original Source: Kotlin and Immutable Collections?



回答2:

Is it legitimate? Well, yes. There are uses cases in which that would make sense.

Is it a good idea? I think not, especially if you're talking about casting a list that was returned by some external library. The cast will fail if someone actually hands you some List implementations that really is immutable and does not implement MutableList. The fact that at the moment (Kotlin 1.0.2), all of Kotlin's Lists are also MutableLists doesn't mean that every List you'll ever see in your code is also an MutableList.



回答3:

Right now if you use listOf() you'll get a List with all methods, which mutate the list, throwing java.lang.UnsupportedOperationException:

val list = listOf(1, 2)

val mlist = list as MutableList

mlist.add(3)

This throws:

Exception in thread "main" java.lang.UnsupportedOperationException
        at java.util.AbstractList.add(AbstractList.java:148)