为了使用集合,这一章节展示了一些来自Kotlin标准库的函数。它自始至终描述了一些相关的特性:
vararg
关键字,允许你声明一个带有任意个参数的函数- 一个让你调用某些仅有一个参数的函数却无需八股代码的中缀标记
- 解构(Destructuring)声明允许你把一个单独的组合值解压为多个变量
3.4.2 扩展Java的集合API
我们以Kotlin中的集合跟Java中的是同样的类但是多了一个扩展API这样的一个想法开始这一章。你看过了获取列表最后一个元素并查找一个数字集中的最大值的例子:
>>> val strings: List<String> = listOf("first", "second", "fourteenth")
>>> strings.last()
fourteenth
>>> val numbers: Collection<Int> = setOf(1, 14, 2)
>>> numbers.max()
14
我们对于它是如何工作的感兴趣:为什么在Kotlin中使用Java库的类来做如此多的事情是可能的。现在答案应该清晰了:last
和max
函数被声明为扩展函数!
last
函数并没有比String
的lastChar
函数跟复杂,在前一章节中已经讨论的:它是List
类的扩展。对于max
,让我们来看一个简化的声明。真实的库函数不仅仅对Int
数字有效,对任意的可比较元素也是有效的:
fun <T> List<T>.last(): T { /* returns the last element */ }
fun Collection<Int>.max(): Int { /* finding a maximum in a collection */ }
Kotlin标准库中声明许多的扩展函数,我们并不会在这里一一列出。你可能会想知道什么是了解Kotlin标准库的全部只是的最佳途径。在任何时候你都不需要这样做--(因为当)你需要用集合或其他对象做一些事情的时候,IDE的代码补全功能将会为你展示该类型的对象所有的可能的、可用的函数。(IDE提供的)列表包含了常规的方法和扩展函数,你可以选择你需要的函数。 在这一章节的开头,你也看到了用来创建集合的函数。这些函数的一个共同的特性是它们可以带任意数量的参数进行调用。在下面的章节中,你将会看到声明这样的函数的语法。
3.4.2 可变参数(Varargs): 可以接受任意个参数的函数
当你调用一个函数来创建一个列表时,你可以向它传递任意数量的声明:
val list = listOf(2, 3, 5, 7, 11)
如果你在查找这个函数在库中是如何被声明的,你将会发现以下代码:
fun listOf<T>(vararg values: T): List<T> { ... }
你可能对Java的可变参数非常熟悉:一个允许你通过以打包成数组的方式传递任意数量的值给一个方法的特性。Kotlin的可变参数跟Java的很像,但是语法有些不同:不是在类型后面用三个点,而是在参数后面使用vararg
修饰符。
Kotlin和Java之间其他的不同点是当你需要传递的参数已经打包在一个数组里面时的函数调用语法。在Java中,你原样传递数组,然而Kotlin却要求你显式的对数组进行拆箱(unpack the array)。技术上讲,这个特性称做使用一个展开操作符(spread operator),但是在实践中,它跟在对应的参数前面放置*
符号一样简单:
fun main(args: Array<String>) {
val list = listOf("args: ", *args) // 1 展开操作符解压(unpack)数组内容
println(list)
}
展开操作符允许你合并来自数组和一些单一调用中的固定值。Java并不支持(这种特性)。 现在让我们继续讨论映射。我们将会简要的讨论了一种提示Kotlin函数调用的可读性的方法:中缀调用(infix call)。
3.4.3 使用元组(pairs):中缀调用和析构声明
为了创建映射,你使用mapOf()
函数:
val map = mapOf(1 to "one", 7 to "seven", 53 to "fifty-three")
这是一个很好的时间点来提供了我们在这一章的开头为你承诺的另一种解释。这行代码中的to
并不是内置的语法,相反的,而是一个方法的特殊调用,叫做中缀调用(infix call)。
在一个中缀调用,方法的名字被放在目标对象名和参数之间,而且没有其他的分隔符。下面的两个调用是等价的:
1.to("one") // 1 以常规的方式来调用
1 to "one" // 2 使用中缀标记来调用函数
中缀调用可以用于带一个参数的常规方法和扩展函数。为了使得函数可以使用中缀标记来调用,你需要用infix
修饰符来标记它。这有一个to
函数的简化版本的声明:
infix fun Any.to(other: Any) = Pair(this, other)
to
函数返回一个Pair
实例。Pair
是Kotlin的一个标准库类,毫不意外的,它表示一对元素。Pair
和to
的实际声明用的是泛型,但是为了简单起见,我们在此忽略它们。
注意,你可以为两个变量直接分配一对元素:
val (number, name) = 1 to "one"
这个特性叫做析构声明(destructuring declaration)。图3.3阐释了元素的析构声明是如何工作的。
图3.3 你用to
函数创建了一个元组并使用析构声明将它拆箱
析构声明这一特性并不局限于元组。举个例子,你也可以为两个独立的变量key
和value
分配一个映射集合。
这一特性对于循环也是有效的,正如你在joinToString()
的实现中看到的,(它)使用了withIndex()
函数:
for ((index, element) in collection.withIndex()) {
println("$index: $element")
}
7.4节将会描述声明时候可以析构一个表达式并将其分配给多个变量。
to
函数是一个扩展函数。你可以创建任何元素的一个元组,这意味着它是一个泛型接收器的扩展:你可以写成 1 to "one" , "one" to 1 , list to list.size()
等。
让我们来看看mapOf
函数的声明:
fun <K, V> mapOf(vararg values: Pair<K, V>): Map<K, V>
像listOf, mapOf
(一类的函数)接受可变数量的参数,但这次参数应该是键值对。
尽管创建一个新的映射集合看起来是Kotlin中的一个特殊语法,但它是一个有着精简语法的常规函数。接下来,我们讨论扩展是如何简化字符串和正则表达式的处理的。