9.1.1.2 构造集合

原文链接: https://kotlinlang.org/docs/constructing-collections.html

9.1.1.2 构造集合

由元素构造

创建集合最常见的方式是使用标准库函数 listOf<T>()、setOf<T>()、mutableListOf<T>()、mutableSetOf<T>()。如果你以逗号分隔的集合元素列表作为实参传入,编译器会自动推断元素类型。创建空集合时,请显式指定类型。

1
2
val numbersSet = setOf("one", "two", "three", "four")
val emptySet = mutableSetOf<String>()

映射也有对应的函数 mapOf() 和 mutableMapOf()。映射的键和值以 Pair 对象的形式传入(通常使用 to 中缀函数创建)。

1
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 1)

请注意,to 写法会创建一个短生命周期的 Pair 对象,因此只有在对性能要求不高时才建议使用它。为避免过多的内存占用,请使用其他方式。例如,你可以创建一个可变映射,然后用写操作填充它。apply() 函数在这里可以帮助你保持初始化过程的流畅书写。

1
val numbersMap = mutableMapOf<String, String>().apply { this["one"] = "1"; this["two"] = "2" }

使用集合构建器函数创建

创建集合的另一种方式是调用构建器函数——buildList()、buildSet() 或 buildMap()。它们会创建相应类型的新可变集合,使用写操作填充它,并返回包含相同元素的只读集合:

1
2
3
4
5
6
7
val map = buildMap { // 这是 MutableMap<String, Int>,键和值的类型根据下面的 `put()` 调用推断
    put("a", 1)
    put("b", 0)
    put("c", 4)
}

println(map) // {a=1, b=0, c=4}

空集合

还有一些用于创建不含任何元素的集合的函数:emptyList()、emptySet() 和 emptyMap()。创建空集合时,应指定集合将要保存的元素类型。

1
val empty = emptyList<String>()

列表的初始化函数

对于列表,有一个类似构造器的函数,它接收列表大小以及一个根据索引定义元素值的初始化函数。

1
2
3
4
fun main() {
    val doubled = List(3, { it * 2 }) // 如果你以后想修改其内容,也可以使用 MutableList
    println(doubled)
}

具体类型构造器

要创建具体类型的集合,例如 ArrayList 或 LinkedList,你可以使用这些类型已有的构造器。Set 和 Map 的实现也有类似的构造器。

1
2
val linkedList = LinkedList<String>(listOf("one", "two", "three"))
val presizedSet = HashSet<Int>(32)

复制

要创建一个与现有集合元素相同的集合,你可以使用复制函数。标准库中的集合复制函数会创建浅拷贝集合,其中的引用指向相同的元素。因此,对某个集合元素所做的修改会反映在它的所有副本中。

集合复制函数,例如 toList()、toMutableList()、toSet() 等,会创建某个集合在特定时刻的快照。它们的结果是包含相同元素的新集合。如果你在原始集合中添加或移除元素,不会影响这些副本。副本也可以独立于源集合进行修改。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Person(var name: String)
fun main() {
    val alice = Person("Alice")
    val sourceList = mutableListOf(alice, Person("Bob"))
    val copyList = sourceList.toList()
    sourceList.add(Person("Charles"))
    alice.name = "Alicia"
    println("First item's name is: ${sourceList[0].name} in source and ${copyList[0].name} in copy")
    println("List size is: ${sourceList.size} in source and ${copyList.size} in copy")
}

这些函数还可以用于把集合转换为其他类型,例如从列表构建集合,或者反过来。

1
2
3
4
5
6
7
fun main() {
    val sourceList = mutableListOf(1, 2, 3)
    val copySet = sourceList.toMutableSet()
    copySet.add(3)
    copySet.add(4)
    println(copySet)
}

另一种方式是创建指向同一个集合实例的新引用。当你用现有集合初始化一个集合变量时,就会创建新的引用。因此,当通过某个引用修改集合实例时,改动会反映在它的所有引用中。

1
2
3
4
5
6
fun main() {
    val sourceList = mutableListOf(1, 2, 3)
    val referenceList = sourceList
    referenceList.add(4)
    println("Source size: ${sourceList.size}")
}

集合的初始化方式可以用来限制可变性。例如,如果你创建了一个指向 MutableList 的 List 引用,那么当你尝试通过该引用修改集合时,编译器会报错。

1
2
3
4
5
6
7
fun main() {
    val sourceList = mutableListOf(1, 2, 3)
    val referenceList: List<Int> = sourceList
    //referenceList.add(4)            //编译错误
    sourceList.add(4)
    println(referenceList) // 显示 sourceList 的当前状态
}

在其他集合上调用函数

集合也可以作为对其他集合执行各种操作的结果而被创建。例如,对列表进行过滤会创建一个包含符合过滤条件元素的新列表:

1
2
3
4
5
fun main() {
    val numbers = listOf("one", "two", "three", "four")
    val longerThan3 = numbers.filter { it.length > 3 }
    println(longerThan3)
}

映射(map)会基于转换结果生成一个列表:

1
2
3
4
5
fun main() {
    val numbers = setOf(1, 2, 3)
    println(numbers.map { it * 3 })
    println(numbers.mapIndexed { idx, value -> value * idx })
}

关联(associate)会生成映射:

1
2
3
4
fun main() {
    val numbers = listOf("one", "two", "three", "four")
    println(numbers.associateWith { it.length })
}

关于 Kotlin 中集合操作的更多信息,请参阅集合操作概览。