集合
与其他语言不同的是,Kotlin区别可变和不可变的集合(列表、集合、Map等)。精确地控制什么时候集合可以被编辑是很有用处的,这会消除一些缺陷,同时也是为了设计更好的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>。
我们可以参考列表和集合的基本用法如下:
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并没有专门创建列表和集合的语法。使用标准库中的方法,比如listOf() , mutableListOf() , setOf() , mutableSetOf()即可。Map的创建并不需要效率关键代码,可以使用一个简单的idiom实现。
mapOf(a to b, c to d)
需要注意的是,只读视图的变量指向同一个列表,并且随着列表的改变而改变。如果列表中存在的引用是只读的变量,我们可以考虑将集合当成完全地不可变的。一个简单的创建这样的集合的方式是:
val items = listOf(1, 2, 3)
当前,listOf方法被实现为使用ArrayList,但是将来更节省内存的不可变集合类型创建方式将会实现,那将开拓新的局面。
需要注意的是只读类型是协变的。这意味着你可以将List<Rectangle>赋值给List<Shape>,假如Rectangle继承自Shape。这样的操作在可变集合类型中是不允许的,因为在运行时可能导致失败。
有时你想要在一个特殊的时间点返回一个集合快照给调用者,这个集合快照被保证不会改变:
class Controller {
private val _items = mutableListOf<String>()
val items: List<String> get() = _items.toList()
}
扩展函数toList仅仅是返回列表的副本,因此,返回的列表不会被改变。列表和集合有很多有用的扩展方法有必要熟悉一下:
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)