[TOC]
好吧..用MarkDown写的..
# Kotlin 标准库常用扩展函数集合
## apply
* apply 是 Any 的扩展函数,因而所有类型都能调用。
* apply 接受一个lambda表达式作为参数,并在apply调用时立即执行,apply返回原来的对象。
* apply 主要作用是将多个初始化代码链式操作,提高代码可读性。
```kotlin
val task = Runnable { println("do something amazing") }
val thread = Thread(task)
thread.setDaemon(true)
thread.start()
```
```kotlin
val task = Runnable { println("do something amazing") }
Thread(task).apply { setDaemon(true) }.start()
```
## let
let 和 apply 类似, 唯一的不同是返回值,let返回的不是原来的对象,而是闭包里面的值,参数为it
```kotlin
val dog = Dog()
print(dog.let {
val ears = "catbro"
val eyes = it.eyes
ear
})
```
## also
also函数的结构实际上和let很像唯一的区别就是返回值的不一样,let是以闭包的形式返回,返回函数体内最后一行的值,如果最后一行为空就返回一个Unit类型的默认值。
而also函数返回的则是传入对象的本身
## with
with 是一个顶级函数, 当你想调用对象的多个方法但是不想重复对象引用
```kotlin
val dog: Dog = Dog()
dog.ears = "dog1"
dog.eyes = "dog2"
...
with(dog) {
ears = "dog1"
eyes = "dog2"
...
}
```
## run
run 是 with和let 的组合
```kotlin
val dog = Dog()
print(dog.run {
legs = "1"
ears = "2"
eyes = it.eyes
legs
})//打印结果为1
```
## use
[引用](https://www.jianshu.com/p/5d2f2ca55dfa)
use是Kotlin的一个内置的扩展函数,它能保证Lambda表达式中的代码全部执行完之后自动将外层的流关闭,这样我们就不需要再写一个finally语句,手动关闭流了。
* 实现了Closeable接口的对象可调用use函数
* use函数会自动关闭调用者(无论中间是否出现异常)
* Kotlin的File对象和IO流操作变得行云流水
* use函数内部实现也是通过try-catch-finally块捕捉的方式,所以不用担心会有异常抛出导致程序退出
* close操作在finally里面执行,所以无论是正常结束还是出现异常,都能正确关闭调用者
```kotlin
File("/home/test.txt").readLines().forEach { println(it) }//readLines这个扩展函数已经间接调用了use
```
## forEachLine
将读到的每行内容回掉到Lambda表达式中
```kotlin
fun load(): String {
val content = StringBuilder()
try {
val input = openFileInput("data")
val reader = BufferedReader(InputStreamReader(input))
reader.use {
reader.forEachLine {
content.append(it)
}
}
} catch (e: IOException) {
e.printStackTrace()
}
return content.toString()
}
```
# 函数式API
## slice
slice操作符顾名思义是"切片"的意思,也就是它可以取集合中一部分元素或者某个元素,最后也是组合成一个新的集合。它有两个重载函数,一个传入IntRange对象指定切片起始位置和终止位置,最后切出的是一个范围的元素加入到新集合中。另一个是传入一个Iterable下标集合,也就会从指定下标分别切出对应的元素,最后放入到新集合中。
过滤一个list中指定index的元素
* **slice by IntRange**一般使用场景: 用于切取一段下标范围的子集合
* **slice by itertar index**一般使用场景: 用于切取某个或者某些下标元素组成的集合
```kotlin
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.slice(1..3))
println(numbers.slice(0..4 step 2))
println(numbers.slice(setOf(3, 5, 0)))
```
## distinct
### distinct
返回一个只包含不同元素的数组
```kotlin
val list = listOf(1, 4, 2, 2)
assertEquals(listOf(1,4,2),list.distinct())
```
### distinctBy
返回集合元素执行指定条件后,不同元素的数组(原始数组元素)
```kotlin
val list = listOf(1, 4, 2, 2)
assertEquals(listOf(1,4),list.distinctBy { it%2 == 0})
```
## filter
filter主要用作过滤器(对集合元素),它的返回值也是一个集合
### filter/filterTo
```kotlin
var items2 = listOf(1, 2, 3, 4)
items2=items2.filter { it % 2 == 0 }
println(items2)
```
### filterIndexed/filterIndexedTo
接受(Int,T)->Boolean类型的函数,同时检查索引和元素是否符合条件
下标筛选,和元素筛选
```kotlin
//筛选 集合中下标是偶数item
val filterIndexList = newList.filterIndexed { index, i -> index % 2 == 0; }
```
### filterIsIntance/filterIsIntanceTo
过滤出特定类型的元素,可以指定一个Class对象
filterIsIntance
```kotlin
open class Animal(val name: String) {
override fun toString(): String {
return name
}
}
class Dog(name: String): Animal(name)
class Cat(name: String): Animal(name)
val animals: List<Animal> = listOf(Cat("Scratchy"), Dog("Poochie"))
val cats = animals.filterIsInstance<Cat>()
println(cats) // [Scratchy]
```
filterIsIntanceTo
```kotlin
val numbers: List<Int> = listOf(0, 1, 2, 3, 4, 8, 6)
val numbersOnSameIndexAsValue = mutableListOf<Int>()
println(numbersOnSameIndexAsValue) // []
numbers.filterIndexedTo(numbersOnSameIndexAsValue) { index, i -> index == i }
println(numbersOnSameIndexAsValue) // [0, 1, 2, 3, 4, 6]
```
### filterNotNull/filterNotNullTo
过滤出非空元素
```kotlin
val list = listOf(1,2,3,null,4)
assertEquals(listOf(1,2,3,4),list.filterNotNull())
```
### filterNot/filterNotTo
过滤出不符合条件的元素
## drop
```kotlin
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.drop(1))
println(numbers.dropLast(5))
println(numbers.dropWhile { it.length == 3 })
println(numbers.dropLastWhile { it.contains('i') })
```
### drop
从第一项开始去除前n个元素,并返回剩余的元素列表。
### dropLast
从最后一项开始去除前n个元素,并返回剩余的元素列表。
### dropLastWhile
根据给定函数从最后一项开始去掉指定元素,直到不满足条件为止的后面的元素,并返回剩余元素的列表。
### dropWhile
根据给定函数从第一项开始去掉指定元素,直到不满足条件为止的前面的元素,并返回剩余元素列表。
## take
```kotlin
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.take(3))
println(numbers.takeLast(3))
println(numbers.takeWhile { !it.startsWith('f') })
println(numbers.takeLastWhile { it != "three" })
user.takeIf { it.name.isNotEmpty() }?.also { println(it.name) } ?: println("姓名为空")
user.takeUnless { it.name.isEmpty() }?.also { println(it.name) } ?: println("姓名为空")
```
### take
返回从第一个开始的n个元素
### takeLast
返回从最后一个开始的n个元素。
### takeLastWhile
返回从最后一个开始符合给定函数条件的元素,直到不符合条件为止
### takeWhile
返回从第一个开始符合给定函数条件的元素,直到不符合条件为止
### takeIf
takeIf的闭包返回一个判断结果,如果为false时takeIf函数返回null;
### takeUnless
takeUnless与takeIf相反,为true时takeUnless函数返回null
## chunked
要将集合分解为给定大小的“块”,请使用 chunked() 函数。 chunked() 采用一个参数(块的大小),并返回一个 List 其中包含给定大小的 List。 第一个块从第一个元素开始并包含 size 元素,第二个块包含下一个 size 元素,依此类推。 最后一个块的大小可能较小。
```kotlin
val numbers = (0..13).toList()
println(numbers.chunked(3))
//[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13]]
println(numbers.chunked(3) { it.sum() }) // `it` 为原始集合的一个块
//[3, 12, 21, 30, 25]
```
## Windowed
可以检索给定大小的集合元素中所有可能区间。 获取它们的函数称为 windowed():它返回一个元素区间列表,比如通过给定大小的滑动窗口查看集合,则会看到该区间。 与 chunked() 不同,windowed() 返回从每个集合元素开始的元素区间(窗口)。 所有窗口都作为单个 List 的元素返回。
```kotlin
val numbers = listOf("one", "two", "three", "four", "five")
println(numbers.windowed(3))
//[[one, two, three], [two, three, four], [three, four, five]]
```
```kotlin
val numbers = listOf("one", "two", "three", "four")
println(numbers.any { it.endsWith("e") })//true
println(numbers.none { it.endsWith("a") })//true
println(numbers.all { it.endsWith("e") })//false
println(emptyList<Int>().all { it > 5 })//true // vacuous truth
val empty = emptyList<String>()
println(numbers.any())//true
println(empty.any())//false
println(numbers.none())//false
println(empty.none())//true
```
## none
是否都不是
```kotlin
val mList2 = arrayListOf(0, 1, 2, 3, 4)
println(mList2.none { it == 5 })//true
```
## all
检查集合中是否所有元素都符合某个条件
```kotlin
val mList2 = arrayListOf(0, 1, 2, 3, 4)
println(mList2.all { it % 2 == 0 })//false
```
## any
检测集合中是否至少存在一个元素满足条件,如果是就返回true
```kotlin
//测试any
val any = list.any { it.age > 10 }
println(any)//true
```
## count
检查集合中有多少个元素满足该条件,返回值是Int
```kotlin
//测试count
val count = list.count { it.age > 25 }
println(count)
```
## contain
### contain
如果指定元素可以在集合找到,则 返回true
```kotlin
val list = listOf(4,1,2,3,4)
assertTrue(list.contains(3))
```
### containAll
如果指定集合所有元素都可以在目标集合找到,则 返回true
```kotlin
val list = listOf(4,1,2,3,4)
val subList = listOf(2,1)
assertTrue(list.containsAll(subList))
```
## average
求集合的平均值(元素之和/元素大小)。仅限(Byte,Short,Int,Long,Float,Double)
```kotlin
val list = listOf(1, 4, 2, 2)
assertEquals(2.25,list.average())
```
## associate
### associate
通过指定的条件,把list转换成map
```kotlin
val list = listOf(1, 2)
assertEquals(mutableMapOf(Pair("a1",1),Pair("a2",2)), list.associate({ it -> Pair("a"+it,it)}))
```
### associateBy
通过指定的条件,把list转换成map。2种,第一只转换map的key;第二map的key-value都转换
```kotlin
val list = listOf(1, 4, 2, 2)
assertEquals(hashMapOf("key1" to 1, "key4" to 4, "key2" to 2), list.associateBy { it -> "key" + it })
assertEquals(hashMapOf("key1" to "value1", "key4" to "value4", "key2" to "value2"),
list.associateBy({ it -> "key" + it }, { it -> "value" + it }))
```
## fold/reduce
依次将所提供的操作应用于集合元素并返回累积的结果。 操作有两个参数:先前的累积值和集合元素。
fold() 接受一个初始值并将其用作第一步的累积值,而 reduce() 的第一步则将第一个和第二个元素作为第一步的操作参数。
```kotlin
val numbers = listOf(5, 2, 10, 4)
val sum = numbers.reduce { sum, element -> sum + element }
println(sum)//21
val sumDoubled = numbers.fold(0) { sum, element -> sum + element * 2 }
println(sumDoubled)//42
//val sumDoubledReduce = numbers.reduce { sum, element -> sum + element * 2 } //错误:第一个元素在结果中没有加倍
//println(sumDoubledReduce)
```
### foldIndexed/reduceIndexed
使用函数 reduceIndexed() 和 foldIndexed() 传递元素索引作为操作的第一个参数。
```kotlin
val numbers = listOf(5, 2, 10, 4)
val sumEven = numbers.foldIndexed(0) { idx, sum, element -> if (idx % 2 == 0) sum + element else sum }
println(sumEven)//15
val sumEvenRight = numbers.foldRightIndexed(0) { idx, element, sum -> if (idx % 2 == 0) sum + element else sum }
println(sumEvenRight)//15
```
### foldRight/reduceRight
如需将函数以相反的顺序应用于元素,可以使用函数 reduceRight() 和 foldRight() 它们的工作方式类似于 fold() 和 reduce(),但从最后一个元素开始,然后再继续到前一个元素。 记住,在使用 foldRight 或 reduceRight 时,操作参数会更改其顺序:第一个参数变为元素,然后第二个参数变为累积值。
```kotlin
val numbers = listOf(5, 2, 10, 4)
val sumDoubledRight = numbers.foldRight(0) { element, sum -> sum + element * 2 }
println(sumDoubledRight)//42
```
### foldRightIndexed/reduceRightIndexed
## forEach
### forEach
```kotlin
val iterator = (1..3).iterator()
// do something with the rest of elements
iterator.forEach {
println("The element is $it")
}
```
### forEachIndexed
ForEachIndexed 遍历数组中的元素并且打印出index索引值
```kotlin
val set = setOf(“1”,“2”,“3”,“4”)
set.forEachIndexed { index, value ->
println("$ index,$ value")
}//可以返回索引值
```
## max/min/average/sum/count
min() 与 max() 分别返回最小和最大的元素;
average() 返回数字集合中元素的平均值;
sum() 返回数字集合中元素的总和;
count() 返回集合中元素的数量;
```kotlin
val numbers = listOf(6, 42, 10, 4)
println("Count: ${numbers.count()}")//Count: 4
println("Max: ${numbers.max()}")//Max: 42
println("Min: ${numbers.min()}")//Min: 4
println("Average: ${numbers.average()}")//Average: 15.5
println("Sum: ${numbers.sum()}")//Sum: 62
```
## maxBy/minBy/maxWith/minWith
maxBy()/minBy() 接受一个选择器函数并返回使选择器返回最大或最小值的元素。
maxWith()/minWith() 接受一个 Comparator 对象并且根据此 Comparator 对象返回最大或最小元素。
```kotlin
val numbers = listOf(5, 42, 10, 4)
val min3Remainder = numbers.minBy { it % 3 }
println(min3Remainder)//42
val strings = listOf("one", "two", "three", "four")
val longestString = strings.maxWith(compareBy { it.length })
println(longestString)//three
```
## sumBy/sumByDouble
sumBy() 使用对集合元素调用返回 Int 值的函数。
sumByDouble() 与返回 Double 的函数一起使用。
```kotlin
val numbers = listOf(5, 42, 10, 4)
println(numbers.sumBy { it * 2 })//122
println(numbers.sumByDouble { it.toDouble() / 2 })//30.5
```
## fatMap
flatMap先对集合中的某个元素映射成集合,再将所有映射成的集合做一个元素平铺,即做一个list
### fatMap
```kotlin
val list = listOf(1, 2)
assertEquals(listOf(1,2,2,4),list.flatMap { it -> listOf(it,it*2) })
```
### fatMapTo
## groupBy
groupBy主要用作将集合按照给定的条件进行分组,即将集合转为map
```kotlin
val numbers = listOf("one", "two", "three", "four", "five")
println(numbers.groupBy { it.first().toUpperCase() })//{O=[one], T=[two, three], F=[four, five]}
println(numbers.groupBy(keySelector = { it.first() }, valueTransform = { it.toUpperCase() }))//{o=[ONE], t=[TWO, THREE], f=[FOUR, FIVE]}
```
### groupBy
### groupByTo
### groupingBy
## map
map主要对集合的元素做映射,可以映射成不同的类型,例如Int到String
映射 转换从另一个集合的元素上的函数结果创建一个集合。 基本的映射函数是 map()。 它将给定的 lambda 函数应用于每个后续元素,并返回 lambda 结果列表。 结果的顺序与元素的原始顺序相同。 如需应用还要用到元素索引作为参数的转换,请使用 mapIndexed()。
如果转换在某些元素上产生 null 值,则可以通过调用 mapNotNull() 函数取代 map() 或 mapIndexedNotNull() 取代 mapIndexed() 来从结果集中过滤掉 null 值
映射转换时,有两个选择:转换键,使值保持不变,反之亦然。 要将指定转换应用于键,请使用 mapKeys();反过来,mapValues() 转换值。 这两个函数都使用将映射条目作为参数的转换,因此可以操作其键与值。
```kotlin
val numbers = setOf(1, 2, 3)
println(numbers.map { it * 3 })//[3, 6, 9]
println(numbers.mapIndexed { idx, value -> value * idx })//[0, 2, 6]
val numbers = setOf(1, 2, 3)
println(numbers.mapNotNull { if ( it == 2) null else it * 3 })//[3, 9]
println(numbers.mapIndexedNotNull { idx, value -> if (idx == 0) null else value * idx })//[2, 6]
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
println(numbersMap.mapKeys { it.key.toUpperCase() })//{KEY1=1, KEY2=2, KEY3=3, KEY11=11}
println(numbersMap.mapValues { it.value + it.key.length })//{key1=5, key2=6, key3=7, key11=16}
```
### map/mapTo
返回一个每个元素都根据给定函数条件转换的数组
### mapIndexed/mapIndexedTo
功能同map,比map多了一个索引
### mapIndexedNotNull/mapIndexedNotNullTo
### mapNotNull/mapNotNullTo
同map。但是,元素转换不包含Null
## elementAt
//查找下标对应元素,如果越界会根据方法返回默认值。
### elementAt
```kotlin
val numbers = linkedSetOf("one", "two", "three", "four", "five")
println(numbers.elementAt(3))//four
val numbersSortedSet = sortedSetOf("one", "two", "three", "four")
println(numbersSortedSet.elementAt(0)) //four// 元素以升序存储
```
### elementAtOrNull/elementAtOrElse
当指定位置超出集合范围时,elementAtOrNull() 返回 null。
elementAtOrElse() 还接受一个 lambda 表达式,该表达式能将一个 Int 参数映射为一个集合元素类型的实例。
当使用一个越界位置来调用时,elementAtOrElse() 返回对给定值调用该 lambda 表达式的结果。
```kotlin
val numbers = listOf("one", "two", "three", "four", "five")
println(numbers.elementAtOrNull(5))//null
println(numbers.elementAtOrElse(5) { index -> "The value for index $index is undefined"})
//The value for index 5 is undefined
```
## first
### first
返回符合条件的第一个元素,没有则抛异常NoSuchElementException
```kotlin
val mList1 = mutableListOf(0, 1, 2, 3, 4, 5)
println(mList1.first())//0
```
### firstOrNull
返回集合第1个元素,如果是空集, 对空指针异常处理的函数,如果集合为空,则返回null。
```kotlin
val mList2 = listOf<Int>()
println(mList2.firstOrNull())//null
```
## find
找到集合中第一个满足条件的元素,返回值是集合元素类型,可能为null
```kotlin
//测试find
val find = list.find { it.age > 25 }
println(find)
```
### find/findLast
## indexOf
### indexOf
返回指定元素的下标,没有就返回-1
```kotlin
println(mList.indexOf(3))//2
println(mList.indexOf(0))//-1
```
### indexOfFirst
返回第一个符合条件的元素的下标,没有就返回-1 。
```kotlin
println(mList.indexOfFirst { it == 2 })//1
```
### indexOfLast
返回最后一个符合条件的元素下标,没有就返回-1 。
## last
### last
返回符合条件的最后一个元素,没有则抛异常NoSuchElementException 。
```kotlin
val mList1 = mutableListOf(0, 1, 2, 3, 4, 5)
println(mList1.last())//5
```
### lastIndexOf
从指定的startIndex开始,返回指定字符串最后一次出现的此字符序列中的索引。
### lastOrNull
如果是空集, 对空指针异常处理的函数,如果集合为空,则返回null。
```kotlin
val mList2 = listOf<Int>()
println(mList2.lastOrNull())//null
```
## single
### single
返回单个元素,如果集合为空或有多个元素,则抛出异常。
```kotlin
val list = listOf(1, 2, 2, 4)
assertEquals(4, list.single { it == 4 })
```
### singleOrNull
返回单个元素,如果数组为空或有多个元素,则返回null。
```kotlin
val list = listOf(1, 2, 2, 4)
assertEquals(null, list.singleOrNull { it == 2 })
```
## reverse
倒序排列集合
```kotlin
val list = listOf(1, 2, 2, 4)
assertEquals(listOf(4,2,2,1), list.reversed())
```
## sort
返回所有元素分类排序列表。
### sort
```kotlin
val list = listOf(1, 4, 2, 2)
assertEquals(listOf(1, 2, 2, 4), list.sorted())
```
### sortBy
返回所有元素分类排序列表。顺序按照指定函数条件排列
```kotlin
val list = listOf(1, 4, 2, 2)
assertEquals(listOf(4,2,2,1), list.sortedBy { -it })
```
### sortByDescending
返回所有元素分类排序列表。顺序按指定函数条件的降序排列
```kotlin
val list = listOf(1, 4, 2, 2)
assertEquals(listOf(4,2,2,1), list.sortedDescending())
```
### sortDescending
返回所有元素分类排序列表。顺序按降序排列
```kotlin
val list = listOf(1, 4, 2, 2)
assertEquals(listOf(4,2,2,1), list.sortedDescending())
```
### sortWith
### sorted
### sortedBy
### sortedByDescending
### sortedDescending
### sortedWith
## partition
把一个指定的集合分割成2个。第一个集合是所有符合指定函数条件的,第二个集合是所有不符合指定条件的集合
```kotlin
val list = mutableListOf(1, 2, 2, 4)
assertEquals(Pair(listOf(2, 2, 4), listOf(1)), list.partition { it % 2 == 0 })
```
## plus / minus
在 Kotlin 中,为集合定义了 plus (+) 和 minus (-) 操作符。 它们把一个集合作为第一个操作数;第二个操作数可以是一个元素或者是另一个集合。 返回值是一个新的只读集合:
plus 的结果包含原始集合 和 第二个操作数中的元素。
minus 的结果包含原始集合中的元素,但第二个操作数中的元素 除外。 如果第二个操作数是一个元素,那么 minus 移除其在原始集合中的 第一次 出现;如果是一个集合,那么移除其元素在原始集合中的 所有出现。
```kotlin
val numbers = listOf("one", "two", "three", "four")
val plusList = numbers + "five"
val minusList = numbers - listOf("three", "four")
println(plusList)//[one, two, three, four, five]
println(minusList)//[one, two]
```
### plus
### plusElement
## zip
合拢 转换是根据两个集合中具有相同位置的元素构建配对。 在 Kotlin 标准库中,这是通过 zip() 扩展函数完成的。 在一个集合(或数组)上以另一个集合(或数组)作为参数调用时,zip() 返回 Pair 对象的列表(List)。 接收者集合的元素是这些配对中的第一个元素。 如果集合的大小不同,则 zip() 的结果为较小集合的大小;结果中不包含较大集合的后续元素。 zip() 也可以中缀形式调用 a zip b 。
也可以使用带有两个参数的转换函数来调用 zip():接收者元素和参数元素。 在这种情况下,结果 List 包含在具有相同位置的接收者对和参数元素对上调用的转换函数的返回值。
### zip
```kotlin
val colors = listOf("red", "brown", "grey")
val animals = listOf("fox", "bear", "wolf")
println(colors zip animals)//[(red, fox), (brown, bear), (grey, wolf)]
val twoAnimals = listOf("fox", "bear")
println(colors.zip(twoAnimals))//[(red, fox), (brown, bear)]
val colors = listOf("red", "brown", "grey")
val animals = listOf("fox", "bear", "wolf")
println(colors.zip(animals) { color, animal -> "The ${animal.capitalize()} is $color"})
//[The Fox is red, The Bear is brown, The Wolf is grey]
```
### unzip
要分割键值对列表
```kotlin
val numberPairs = listOf("one" to 1, "two" to 2, "three" to 3, "four" to 4)
println(numberPairs.unzip())//([one, two, three, four], [1, 2, 3, 4])
```
### zipWithNext
```kotlin
val letters = ('a'..'f').toList()
val pairs = letters.zipWithNext()
println(letters) // [a, b, c, d, e, f]
println(pairs) // [(a, b), (b, c), (c, d), (d, e), (e, f)]
val values = listOf(1, 4, 9, 16, 25, 36)
val deltas = values.zipWithNext { a, b -> b - a }
println(deltas) // [3, 5, 7, 9, 11]
```
# 解构
Kotlin中使用operator关键字修饰函数,这样可以将一个函数标记为重载一个操作符或者实现一个约定。使用operator关键字修饰函数并且函数名只能为component1、component2、component3…时就是实现一个约定。
通过将该类实例赋值给一组变量,Kotlin可以直接将对应函数的值按照component1、component2、component3…的顺序赋值给该组变量,这个过程就叫"解构"。
```kotlin
class User(var age: Int, var name: String){
operator fun component1() = age
operator fun component2() = name
}
fun main(args: Array<String>) {
val user = User(11, "Irving")
//将该类实例赋值给一组变量
val (age, name) = user
println(age)
println(name)
}
```