我有一个关于 Kotlin 集合的一般性问题。
当我们有 MutableList
时,为什么会有这么多集合的可变版本(如 val
)对比 var
区别?
嗯……好吧……其实我明白val
与对象的“可变性”无关,而是与对象的“可重新初始化”有关。
但是这就提出了一个问题....为什么不是 MutableList
默认?
最佳答案
TL;博士
单独地,可变和不可变集合能够公开在单个接口(interface)中不能共存的有用功能:
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 ofMutableList<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/