kotlin - 为什么 Kotlin 有可变版本的集合?

标签 kotlin language-design mutablelist

我有一个关于 Kotlin 集合的一般性问题。
当我们有 MutableList 时,为什么会有这么多集合的可变版本(如 val )对比 var区别?
嗯……好吧……其实我明白val与对象的“可变性”无关,而是与对象的“可重新初始化”有关。
但是这就提出了一个问题....为什么不是 MutableList默认?

最佳答案

TL;博士
单独地,可变和不可变集合能够公开在单个接口(interface)中不能共存的有用功能:

  • 可以读取和写入可变集合。但是 Kotlin 努力避免所有运行时故障,因此,这些可变集合是不变的。
  • 不可变集合是协变的,但它们是……嗯……不可变的。尽管如此,Kotlin 确实提供了使用这些不可变集合做有用事情的机制(例如过滤值或从现有的不可变集合创建新的不可变集合)。您可以通过the long list of convenience functions for Kotlin's (immutable) List interface举些例子。

  • Kotlin 中的不可变集合不能添加或删除元素;它们只能从中读取。但是这种明显的限制使得对不可变集合进行一些子类型化成为可能。来自 Kotlin 文档:

    The read-only collection types are covariant...the collection types have the same subtyping relationship as the element types.


    这意味着,如果 Rectangle类是 Shape 的子级上课,你可以放一个List<Rectangle> List<Shape> 中的对象需要时可变:
    fun stackShapes(val shapesList: List<Shape>) {
        ...
    }
    
    val rectangleList = listOf<Rectangle>(...)
    
    // This is valid!
    stackShapes(rectangleList)
    
    另一方面,可变集合可以读取和写入。正因为如此,它们不可能有子类型或父类(super class)型。来自 Kotlin 文档:

    ...mutable collections aren't covariant; otherwise, this would lead to runtime failures. If MutableList<Rectangle> was a subtype of MutableList<Shape>, you could insert other Shape inheritors (for example, Circle) into it, thus violating its Rectangle type argument.


    val rectangleList = mutableListOf<Rectangle>(...);
    val shapesList: MutableList<Shape> = rectangleList // MutableList<Rectangle>-type object in MutableList<Shape>-type variable
    
    val circle = Circle(...)
    val shape: Shape = circle // Circle-type object in Shape-type variable
    
    // Runtime Error!
    shapesList.add(shape) // You're actually trying to add a Circle to a MutableList<Rectangle>
    // If rectanglesList couldn't be put into a variable with type MutableList<Shape> in the first place, you would never have run into this problem.
    
    此时,您可能会想:“那又怎样?Kotlin 可以只为可变集合的所有写入方法添加类型检查......然后您可以允许它们是协变的,并且您不需要单独的不可变收藏品!”
    这是真的,只是它会完全违背 Kotlin 的核心哲学;避免nulls和运行时错误尽可能。你看,这样一个 Collection 的方法必须返回 null - 或引发异常 - 每当类型检查失败时。这只会在运行时变得明显,因为可以通过简单地使可变集合保持不变来避免这种情况......这正是 Kotlin 所做的。

    关于kotlin - 为什么 Kotlin 有可变版本的集合?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63346571/

    相关文章:

    kotlin - 在 map 中查找键与 kotlin 中的firstOrNull

    language-design - 为什么很多语言都缺少逻辑异或运算符?

    language-design - 定义问题而不是解决方案的编程语言?

    Scala 2.13用什么代替MutableList?

    java - 无法使用文件提供程序共享图像 java.lang.SecurityException : Permission Denial: reading androidx. core.content.FileProvider uri

    android - 当导航到可组合时,我们如何隐藏 BottomAppBar(包含导航)?

    android - 在 Kotlin 中进行单元测试的 BuildConfigField 模拟

    scala - 为什么有些集合类除了类方法之外还有一个 "empty"实例方法?

    kotlin - Kotlin 泛型中列表和可变列表的区别