一. 解构声明简介
解构声明,可以将一个对象解构成多个变量,像下面这样
val p = Point(10, 20)
val (x, y) = p
print(x) //10
print(y) //20
一个解构声明同时创建多个变量,并且可以单独使用这些变量。对于每一个解构的变量,在访问时,实际最终都会调用解构对象的componentN()方法,而N就是声明时括号里变量的位置,从1开始。
二. 使用
1. for 循环中使用
例如
val list = listOf(Point(10, 20), Point(30, 40), Point(50, 60))
for ((a, b) in list) {
print(a * b) //200,1200,3000
}
或者迭代一个map
for((key , value ) in map){
// ...
}
注意:如果解构的变量有未使用的,建议用 "_" 表示
val (_, status) = getResult()
print(status)
2. 一个函数返回两个或多个值
示例
data class Result(val result: Int, val status: Status)
fun function(……): Result {
// 各种计算
return Result(result, status)
}
// 现在,使用该函数:
val (result, status) = function(……)
因为数据类自动声明 componentN() 函数,所以这里可以用解构声明。
注意:我们也可以使用标准类 Pair 并且让 function() 返回 Pair
val (a, b) = getPair()
val (x, y, z) = getTriple()
fun getPair(): Pair {
return Pair("hhh", 666)
}
fun getTriple(): Triple {
return Triple("hhh", 233, 2.33f)
}
这里的Pair、Triple也就是元组。
3. 解构声明和lambda表达式
可以对 lambda 表达式参数使用解构声明语法。 如果 lambda 表达式具有 Pair 类型(或者 Map.Entry 或任何其他具有相应 componentN 函数的类型)的参数,那么可以通过将它们放在括号中来引入多个新参数来取代单个新参数:
map.mapValues { entry -> "${entry.value}!" } //替换为下面这行
map.mapValues { (key, value) -> "$value!" }
注意声明两个参数和声明一个解构对来取代单个参数之间的区别:
{ a //-> …… } // 一个参数
{ a, b //-> …… } // 两个参数
{ (a, b) //-> …… } // 一个解构对
{ (a, b), c //-> …… } // 一个解构对以及其他参数
如果解构的参数中的一个组件未使用,那么可以将其替换为下划线,以避免编造其名称:
map.mapValues { (_, value) -> "$value!" }
可以指定整个解构的参数的类型或者分别指定特定组件的类型:
map.mapValues { (_, value): Map.Entry -> "$value!" }
map.mapValues { (_, value: String) -> "$value!" }
三. 自定义一个可解构声明的类
例子:
class Point(var x: Int, var y: Int) {
operator fun component1() = x
operator fun component2() = y
}
这个是刚才上面例子中使用到的Point类,上面也说到解构声明的变量最后都要调用对象的componentN 方法,所以要想让一个类的对象支持解构声明,就必须实现componentN 方法,同时方法前需要加上operator关键字。
data class 自动实现了相关方法支持解构声明,所以data class 实际上自动生成了很多方法,在Android开发中有方法数限制,需要注意。
四. 元组相关
上面提到的Pair、Triple 就是Kotlin 中内置提供的元组,他们可以用于函数返回多个值,也可以作为一种数据结构使用,他们可以解构声明。同时因为他们实现了Serializable接口,在Android开发中也可以通过Intent传递。
//Acitivty1
startActivity(intent.apply { putExtra("hhh", Pair(1, 2)) })
//Activity2
val (a, b) = intent.getSerializableExtra("hhh") as Pair<*, *>
println("a = $a , b = $b") //输出:a = 1 , b = 2
我们也可以可以根据实现元组的一个规范自定义元组,看一下Pair的源码
Pair
public data class Pair(
public val first: A,
public val second: B) : Serializable {
/**
* Returns string representation of the [Pair] including its [first] and [second] values.
*/
public override fun toString(): String = "($first, $second)"
}