和其他大多数语言不同,Kotlin将集合(list,set,map等)区分为可变的和不可变的。精确控制什么时候集合可编辑有助于消除bug和设计良好的API。
了解可变集合的只读视图与实际不可变集合之间的区别很重要。两者都很容易创建,但是类型系统并没有表现出差异,所以由你跟踪(如果它是相关的)。
Kotlin中的List<out T>
类型是一个接口,它提供了只读操作,如size()
,get
和其他。和Java一样,它继承自Collection<T>
进而继承自Iterable<T>
。改变集合的方法被添加至MutableList<T>
接口。这种模式同样适用于Set<out T>/MutableSet<T>
和Map<K, out V>/MutableMap<K, V>
。
我们可以看一下list和set类型的基本用法:
val numbers: MutableList<Int> = mutableListOf(1, 2, 3)
val readOnlyView: List<Int> = 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)
Kotlin不支持适用构造器语法创建list或set。需要使用标准库的方法,如listOf()
,mutableListOf()
, setOf()
, mutableSetOf()
。Map的创建在非性能关键代码中可以用简单的方法:mapOf(a to b,c to d)
。
请注意,readOnlyView
变量(与变量numbers
)指向相同的集合,并且随着底层列表的更改而改变。如果一个list只存在只读引用,我们可以认为该集合完全不可变。创建这样的集合的更简单的方法是:
val items = listOf(1, 2, 3)
当前,listOf
方法是使用数组列表实现的,但是在以后,内存效率更高的完全不可变的集合类型将被使用,到时候它们知道它们不能改变将成为事实。
注意:只读类型是协变的。如果Rectangl
e继承自Shape
,则可以吧一个List<Rectangle>
赋值给List<Shape>
。对于可变集合类型,这样做则是不允许的,因为会导致运行时异常。
有时你想返回给调用者一个集合在某一时刻的快照,并且保证返回的值是不会改变的:
class Controller {
private val _items = mutableListOf<String>()
val items: List<String> get() = _items.toList()
}
扩展方法toList
仅仅复制了集合的条目,因此返回的列表可以保证不会发生变化。
List和set有许多有用的扩展方法值的我们了解:
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()
...和其他你所期望的实用工具,如sort,zip,fold,reduce等。
Map也遵循同样的模式,它们可以很容易的实例化和访问,如下:
val readWriteMap = hashMapOf("foo" to 1, "bar" to 2)
println(readWriteMap["foo"]) // prints "1"
val snapshot: Map<String, Int> = HashMap(readWriteMap)