Kotlin集合

集合

與大多數語言不同,Kotlin 區分可變集合和不可變集合(lists、sets、maps 等)。精確控制什麼時候集合可編輯有助於消除 bug 和設計良好的 API。

預先了解一個可變集合的只讀 視圖 和一個真正的不可變集合之間的區別是很重要的。它們都容易創建,但類型系統不能表達它們的差別,所以由你來跟蹤(是否相關)。

Kotlin 的 List<out T> 類型是一個提供只讀操作如 sizeget等的接口。和 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 沒有專門的語法結構創建 list 或 set。 要用標準庫的方法,如
listOf()mutableListOf()setOf()mutableSetOf()
在非性能關鍵代碼中創建 map 可以用一個簡單的慣用法來完成:mapOf(a to b, c to d)

注意上面的 readOnlyView 變量(譯者注:與對應可變集合變量 numbers)指向相同的底層 list 並會隨之改變。 如果一個 list 只存在只讀引用,我們可以考慮該集合完全不可變。創建一個這樣的集合的一個簡單方式如下:

val items = listOf(1, 2, 3)

目前 listOf 方法是使用 array list 實現的,但是未來可以利用它們知道自己不能變的事實,返回更節約內存的完全不可變的集合類型。

注意這些類型是協變的。這意味着,你可以把一個 List<Rectangle> 賦值給 List<Shape> 假定 Rectangle 繼承自 Shape。對於可變集合類型這是不允許的,因爲這將導致運行時故障。

有時你想給調用者返回一個集合在某個特定時間的一個快照, 一個保證不會變的:

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)