kotlin - 为什么 Kotlin 有可变版本的集合?
问题描述
我有一个关于 Kotlin 集合的一般性问题。
MutableList
当我们有val
vsvar
区别时,为什么会有这么多集合的可变版本(比如)?
好吧....好吧...实际上,我知道这val
与对象的“可变性”无关,而是与对象的“可重新初始化”有关。
但这提出了一个问题....为什么不是MutableList
默认值?
解决方案
TL;博士
单独地,可变和不可变集合能够公开在单个接口中不能共存的有用功能:
- 可以读取和写入可变集合。但是 Kotlin 努力避免所有运行时故障,因此,这些可变集合是不变的。
- 不可变集合是协变的,但它们是……嗯……不可变的。尽管如此,Kotlin 确实提供了使用这些不可变集合做有用事情的机制(例如过滤值或从现有的不可变集合创建新的不可变集合)。您可以浏览Kotlin(不可变)接口的一长串便利函数
List
作为示例。
Kotlin 中的不可变集合不能添加或删除元素;它们只能从中读取。但是这种明显的限制使得对不可变集合进行一些子类型化成为可能。来自 Kotlin 文档:
只读集合类型是协变的……集合类型与元素类型具有相同的子类型关系。
这意味着,如果一个Rectangle
类是一个类的子Shape
类,您可以在需要时将一个List<Rectangle>
对象放入一个List<Shape>
变量中:
fun stackShapes(val shapesList: List<Shape>) {
...
}
val rectangleList = listOf<Rectangle>(...)
// This is valid!
stackShapes(rectangleList)
另一方面,可变集合可以读取和写入。正因为如此,它们不可能有子类型或超类型。来自 Kotlin 文档:
...可变集合不是协变的;否则,这将导致运行时失败。如果
MutableList<Rectangle>
是 的子类型MutableList<Shape>
,则可以将其他 Shape 继承者(例如 Circle)插入其中,从而违反其 Rectangle 类型参数。
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 所做的。
推荐阅读
- html - 图像未相对于其父级调整大小
- qt - 如何使从 qml 组件初始化的 QWidget 的背景透明?
- python - 如何在没有 Context.invoke 或 Context.forward 的情况下“自调用”python-click CLI 命令?
- python - python中的Numba用于更快的哈希
- java - 如何部分重绘画布的非矩形部分
- java - 保护 Java 应用程序免受 SQL 注入
- python-3.x - 仅针对某些文件中的行过滤 Python 日志
- android - 如何使用设置的全跨度或动态 GridCells 数来实现 LazyVerticalGrid。在 jetpack compose 中固定?
- python - 我的代码正在运行但在 15 分钟后停止如何让它无限运行?
- php - 具有不同行和列的 JSON 到 HTML 表