04-成员解构
7.1.3 成员解构
所谓解构声明就是将一个对象解构为多个成员变量,这也就意味着一个解构声明会同时创建多个变量。例如,数据类Person有name和age两个属性。
data class Person(var name: String, var age: Int) {
…
}
对于解构声明来说,任何表达式都可以出现在解构声明的右侧,只要满足对它调用所需数量的component函数即可,特殊情况下,对于componentN()函数则需要用operator关键字修饰。对于上面的实例,当我们对Person数据类使用解构声明时,数据类Person的属性值被分别赋值给了name和age两个变量。
var person = Person("jack", 20)
var (name, age) = person
代码的第二行就是一个解构声明,它的作用是创建两个变量name和age,同时将数据类的属性值分别赋值给name和age。解构声明在编译时会自动声明component函数,上面的Person数据类,编译时将被分解为如下代码。
val name = person.component1()
val age = person.component2()
解构声明不仅可以针对于某一个实例,还可以用在for循环中,格式如下。
for ((a, b) in collection) { …… }
在解构声明中使用for循环,需要集合中的每个元素都提供componentN()方法。为了方便理解,我们来看一个具体的例子。
fun main(args: Array<String>) {
var personA: Person = Person("Door", 22, "ShanDong")
var personB: Person = Person("Green", 30, "BeiJing")
var personC: Person = Person("Dark", 23, "YunNan")
var pers = listOf(personA, personB, personC)
for ((name, age) in pers) {
println("name: $name, age: $age")
}
}
data class Person(var name: String, var age: Int,var province:String)
运行上面的代码,输出结果如下。
name: Door, age: 22
name: Green, age: 30
name: Dark, age: 23
自Kotlin 1.1版本开始,对于解构声明中不需要的某个变量可以使用下划线取代其名称,代码如下。
var (_,age,province)=Person() //不需要使用的变量使用下划线代替
解构声明还可以结合Map使用,但必须满足以下两个条件。
- 提供一个iterator()函数,将映射表示为一个值的序列。
- 提供函数component1()和component2(),将每个元素呈现为一对。
事实上,Kotlin的标准库也确实提供了这样的函数扩展,相关源码如下。
operator fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = entrySet().iterator()
operator fun <K, V> Map.Entry<K, V>.component1() = getKey()
operator fun <K, V> Map.Entry<K, V>.component2() = getValue()
因此,在for循环中对映射使用解构声明的方式如下。
for ((key, value) in map) {
//使用该 key、value 进行具体的操作
}
为了方便理解,来看一个具体的实例。
fun main(args: Array<String>) {
var map= mutableMapOf<String,String>()
map.put("name","Kotlin")
map.put("sex","男")
map.put("age","13")
for ((key,value) in map){
println("$key=$value")
}
}
运行上面的代码,输出结果如下。
name=Kotlin
sex=男
age=13
自1.1版本开始,Kotlin允许在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<Int, String> -> "$value!" }
map.mapValues { (_, value: String) -> "$value!" }