與大多數(shù)語言不同,Kotlin 區(qū)分可變集合和不可變集合(lists、sets、maps 等)。精確控制什么時候集合可編輯有助于消除 bug 和設(shè)計良好的 API。
預先了解一個可變集合的只讀 視圖 和一個真正的不可變集合之間的區(qū)別是很重要的。它們都容易創(chuàng)建,但類型系統(tǒng)不能表達它們的差別,所以由你來跟蹤(是否相關(guān))。
Kotlin 的 List<out T> 類型是一個提供只讀操作如 size、get等的接口。和 Java 類似,它繼承自 Collection<T> 進而繼承自 Iterable<T>。改變 list 的方法是由 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) // 輸出 "[1, 2, 3]"
numbers.add(4)
println(readOnlyView) // 輸出 "[1, 2, 3, 4]"
readOnlyView.clear() // -> 不能編譯
val strings = hashSetOf("a", "b", "c", "c")
assert(strings.size == 3)
Kotlin 沒有專門的語法結(jié)構(gòu)創(chuàng)建 list 或 set。 要用標準庫的方法,如listOf()、 mutableListOf()、 setOf()、 mutableSetOf()。
在非性能關(guān)鍵代碼中創(chuàng)建 map 可以用一個簡單的慣用法來完成:mapOf(a to b, c to d)
注意上面的 readOnlyView 變量(譯者注:與對應(yīng)可變集合變量 numbers)指向相同的底層 list 并會隨之改變。 如果一個 list 只存在只讀引用,我們可以考慮該集合完全不可變。創(chuàng)建一個這樣的集合的一個簡單方式如下:
val items = listOf(1, 2, 3)
目前 listOf 方法是使用 array list 實現(xiàn)的,但是未來可以利用它們知道自己不能變的事實,返回更節(jié)約內(nèi)存的完全不可變的集合類型。
注意這些類型是協(xié)變的。這意味著,你可以把一個 List<Rectangle> 賦值給 List<Shape> 假定 Rectangle 繼承自 Shape。對于可變集合類型這是不允許的,因為這將導致運行時故障。
有時你想給調(diào)用者返回一個集合在某個特定時間的一個快照, 一個保證不會變的:
class Controller {
private val _items = mutableListOf<String>()
val items: List<String> get() = _items.toList()
}
這個 toList 擴展方法只是復制列表項,因此返回的 list 保證永遠不會改變。
List 和 set 有很多有用的擴展方法值得熟悉:
val items = listOf(1, 2, 3, 4)
items.first() == 1
items.last() == 4
items.filter { it % 2 == 0 } // 返回 [2, 4]
val rwList = mutableListOf(1, 2, 3)
rwList.requireNoNulls() // 返回 [1, 2, 3]
if (rwList.none { it > 6 }) println("No items above 6") // 輸出“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"]) // 輸出“1”
val snapshot: Map<String, Int> = HashMap(readWriteMap)