通常情况下一个变量只能携带一个值,解决方法是自定义一个类,写法过于复杂(定义很多字段、不同字段组合都要专门定义构造),而元组可以把多个值同时赋值给一个变量。
可以用于函数返回多个值,也可以作为一种数据结构使用,他们可以解构声明,同时因为他们实现了Serializable接口,在Android开发中也可以通过Intent传递。
Pair 二元元组:可以携带两个值
Tuple 三元元组:可以携带三个值
val two: Pair = Pair("张三", 18)
val three = Triple(22.3, "李四", true) //自动类型推断:Triple
println("三元元祖:${three.first}、${three.second}、${three.third}")
一个函数返回多个值(返回数据类对象或者元组)
fun getPair(): Pair {
return Pair("hhh", 666)
}
val (a, b) = getPair()
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
可以根据元组的原码自定义元组
public data class Triple(
public val first: A,
public val second: B,
public val third: C
) : Serializable {
public override fun toString(): String = "($first, $second, $third)"
}
有时候获取一个对象的属性会定义很多变量去接收,使用解构声明能一次性给多个变量同时赋值。对于每一个解构的变量,在访问时实际最终都会调用解构对象的componentN()方法,而N就是声明时括号里变量的位置,从1开始。
val person = Person("张三", 18)
//通常
var name = person.name
var age = person.age
//解构声明
val (name, age) = person //声明了两个变量,可以单独使用
println(name) // 打印:张三
println(age) // 打印:18
//解构元祖
val (a, b) = Pair(4, "5")
println("$a,$b") //打印:4,5
val (i, j, k) = Triple(1, "a", 2.0)
println(i.javaClass.name+","+j.javaClass.name+","+k.javaClass.name) //打印:int,java.lang.String,double
自定义解构声明的类
想让一个普通的类支持解构声明,就必须实现componentN() 函数,同时方法前需要加上operator关键字。数据类 自动实现了相关方法支持解构声明。
class Point(var x: Int, var y: Int) {
operator fun component1() = x
operator fun component2() = y
}
在数组集合中使用
//Array
val array = arrayOf(1, 2, 3, 4)
val (a1, a2, a3, a4) = array
//Collection
val list = listOf(1, 2, 3)
val (b1, b2, b3) = list
//Map
for ((key, value) in map) {
println("$key-$value")
}
在Lambda中使用
如果 lambda 表达式具有 Pair 类型(或者 Map.Entry 或任何其他具有相应 componentN 函数的类型)的参数,那么可以通过将它们放在括号中来引入多个新参数来取代单个新参数。
map.mapValues { entry -> "${entry.value}!" } //替换为下面这行
map.mapValues { (key, value) -> "$value!" }
{ a //-> …… } // 一个参数
{ a, b //-> …… } // 两个参数
{ (a, b) //-> …… } // 一个解构对
{ (a, b), c //-> …… } // 一个解构对以及其他参数
忽略不需要的解构值
解构中有用不到的值,可以使用下划线代替,省略掉不必要的声明(命名),也不会调用相应的 compoentN() 方法了。
map.mapValues { (_, value) -> "$value!" }
val book = Book(1, "英语")
val (id, _) = book