2.9数组(集合)与区间
数组
数组在 Kotlin 中由 Array 类表示,有 get
和 set
方法(通过运算符重载可以由[]调用),以及 size
方法,以及一些常用的函数:
class Array<T> private constructor() {
val size: Int
operator fun get(index: Int): T
operator fun set(index: Int, value: T): Unit
operator fun iterator(): Iterator<T>
// ...
}
我们可以给库函数 arrayOf()
传递每一项的值来创建Array
, arrayOf(1, 2,3)
创建了一个[1, 2, 3]
这样的数组。也可以使用库函数 arrayOfNulls()
创建一个指定大小的空Array
。
或者通过指定Array大小并提供一个通过索引产生数组元素值的工厂函数:
// 创建一个 Array<String> 内容为 ["0", "1", "4", "9", "16"]
val asc = Array(5, {i -> (i * i).toString() })
像我们上面提到的, []
操作符表示调用 get()
和 set()
函数
注意:和 java 不一样,
arrays
在 kotlin 中是不可变的。这意味这 kotlin 不允许我们把Array<String>
转为Array<Any>
,这样就阻止了可能的运行时错误(但你可以使用 Array
Kotlin 有专门的类来表示原始类型从而避免过度装箱: ByteArray
, ShortArray
,IntArray
等等。这些类与 Array
没有继承关系,但它们有一样的方法与属性。每个都有对应的库函数:
val x: IntArray = intArrayOf(1, 2, 3)
x[0] = x[1] + x[2]
map/list
转换 map 的最好办法可能是下面这样:
for ((key, value) in map) {
}
为了让这个可以工作,我们需要通过提供 iterator() 函数序列化呈现 map 通过 component1() 和component1() 函数是把元素成对呈现事实上,标准库提供了这样的扩展:
fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = entrySet().iterator()
fun <K, V> Map.Entry<K, V>.component1() = getKey()
fun <K, V> Map.Entry<K, V>.component2() = getValue()
因此你可以用 for 循环方便的读取 map (或者其它数据集合)。
把熟悉值存储在 map 中是一种常见的使用方式,这种操作经常出现在解析 JSON 或者其它动态的操作中。这种情况下你可以使用 map 来代理它的属性。
class User(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
在这个例子中,构造函数接受一个 map :
val user = User(mapOf(
"name" to "John Doe",
"age" to 25
))
代理属性将从这个 map 中取指(通过属性的名字):
println(user.name) // Prints "John Doe"
println(user.age) // Prints 25
var 属性可以用 MutableMap 代替只读的 Map :
class MutableUser(val map: MutableMap<String, Any?>) {
var name: String by map
var age: Int by map
}
集合
与大多数语言不同,Kotlin 区分可变集合和不可变集合(lists
、sets
、maps
等)。精确控制什么时候集合可编辑有助于消除 bug 和设计良好的 API。预先了解一个可变集合的只读视图 和一个真正的不可变集合之间的区别是很重要的。它们都容易创建,但类型系统不能表达它们的差别,所以由你来跟踪(是否相关)。
Kotlin 的 List<out T>
类型是一个提供只读操作如 size
、get
等的接口。和 Java 类似,它继承自 Collection<T>
进而继承自Iterable<T>
。改变 list
的方法是由 MutableList<T>
加入的。这一模式同样适用于 Set<out T>
/MutableSet<T>
及 Map<K, outV>
/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
有时你想给调用者返回一个集合在某个特定时间的一个快照, 一个保证不会变的:
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)
区间
区间表达式由具有操作符形式 ..
的 rangeTo
函数辅以 in
和 !in
形成。 区间是为任何可比较类型定义的,但对于整型原生类型,它有一个优化的实
现。以下是使用区间的一些示例
if (i in 1..10) { // 等同于 1 <= i && i <= 10
println(i)
}
整型区间( IntRange
、 LongRange
、 CharRange
)有一个额外的特性:它们可以迭代。 编译器负责将其转换为类似 Java 的基于索引的 for-循环
而无额外开销。
for (i in 1..4) print(i) // 输出“1234”
for (i in 4..1) print(i) // 什么都不输出
如果你想倒序迭代数字呢?也很简单。你可以使用标准库中定义的 downTo()
函数
for (i in 4 downTo 1) print(i) // 输出“4321”
能否以不等于 1 的任意步长迭代数字? 当然没问题, step()
函数有助于此
for (i in 1..4 step 2) print(i) // 输出“13”
for (i in 4 downTo 1 step 2) print(i) // 输出“42”
要创建一个不包括其结束元素的区间,可以使用 until
函数:
for (i in 1 until 10) { // i in [1, 10) 排除了 10
println(i)
}
使用ranges
for (i in 1..100) { ... } // 闭区间: 包括100
for (i in 1 until 100) { ... } // 半开区间: 不包括100
for (x in 2..10 step 2) { ... } //步长为2
for (x in 10 downTo 1) { ... } //降序循环
if (x in 1..10) { ... } //判断x是否在1到10(闭区间)之间的数中
[上一篇:2.8智能转换] [返回目录] [下一篇:3.1Lambda]