Kotlin Reference: Collections

  Kotlin 会区分可变(Mutable)和不可变(Immutable)集合(如 List、Set、Map 等),这一点与其他语言不同。通过对集合能否被修改进行精确的控制,有助于消除 Bug 和设计优良的 API。

  首先,需要理解可变集合的只读视图(View)和一个真正不可变集合间的区别。二者都很容易创建,但在类型系统中并不会体现出区别,你可以根据实际需要来决定是否对二者进行区分。

  Kotlin 的 List<out T> 类型是一个提供了如 sizeget 等只读操作的接口。它继承自 Collection<T>,继而继承自 Iterable<T>,就像 Java。

  MutableList<T> 加入修改列表的方法。Set<out T> / MutableSet<T>Map<K, out V> / MutableMap<K, V> 都使用了这种模式。

  下面展示了 List 和 Set 类型的基本用法:

[code lang=”kotlin”]val numbers: MutableList = mutableListOf(1, 2, 3)
val readOnlyView: List = numbers
println(numbers) // prints “[1, 2, 3]”
numbers.add(4)
println(readOnlyView) // prints “[1, 2, 3, 4]”
readOnlyView.clear() // -> does not compile

val strings = hashSetOf(“a”, “b”, “c”, “c”)
assert(strings.size == 3)[/code]

  Kotlin 并没有创建 List 和 Set 的专用语法,使用标准库提供的如 listOf()mutableListOf()setOf()mutableSetOf() 等方法即可。如果对性能没有严格要求,可以使用这种简单的惯用方式来创建映射:mapOf(a to b, c to d)

  注意上面代码中的 readOnlyView 变量指向的是与 numbers 相同的列表,会随着底层列表的改变而改变。如果某个列表只被只读变量引用,则可以认为该列表是完全不可变的,此类列表可以简单地创建如下:

[code lang=”kotlin”]val items = listOf(1, 2, 3)[/code]

  目前 listOf 方法是使用一个数组列表实现的,但未来该方法会利用集合不能被修改的事实(items 使用 val 声明为只读),返回更加节约内存的完全不可变集合类型。

  注意只读类型是协变的,这意味着如果 Rectangle 继承自 Shape, 就可以把 List<Rectangle> 赋给 List<Shape>;但这对于可变集合类型是不允许的,因为可能会在运行时导致错误。

  有时候,你可能希望向调用者返回集合在某一时刻的一个快照,这个快照是确保不会改变的:

[code lang=”kotlin”]class Controller {
private val _items = mutableListOf()
val items: List get() = _items.toList()
}[/code]

  toList() 扩展方法会复制列表中的元素,由此确保返回的列表不会改变。

  List 和 Set 有很多有用的扩展方法:

[code lang=”kotlin”]val items = listOf(1, 2, 3, 4)
items.first() == 1
items.last() == 4
items.filter { it % 2 == 0 } // returns [2, 4]

val rwList = mutableListOf(1, 2, 3)
rwList.requireNoNulls() // returns [1, 2, 3]
if (rwList.none { it > 6 }) println(“No items above 6”) // prints “No items above 6”
val item = rwList.firstOrNull()[/code]

此外还有众多工具方法,如 sortzipfoldreduce 等等。

  映射也遵守同样的模式,可以像下面一样简单地实例化和访问:

[code lang=”kotlin”]val readWriteMap = hashMapOf(“foo” to 1, “bar” to 2)
println(readWriteMap[“foo”]) // prints “1”
val snapshot: Map = HashMap(readWriteMap)[/code]