------《Kotlin系列之扩展函数》
相比Java, Kotlin提供了不少高级语法特性。对于一个Kotlin的初学者来说经常会写出一些不够优雅的代码。在Kotlin中的源码标准库(Standard.kt)中提供了一些Kotlin扩展的内置函数可以优化kotlin的编码。
扩展函数:let
let扩展函数的实际上是一个作用域函数,当你需要去定义一个变量在一个特定的作用域范围内,let函数的是一个不错的选择;let函数另一个作用就是可以避免写一些判断null的操作。
var result = object?.let{//表示object不为null的条件下,才会去执行let函数体
it.todo() //用it代替了object
1000 //最后一行为返回值(所以返回值类型也根据最后一行类型变化)
}
场景一: 最常用的场景就是使用let函数处理需要针对一个可null的对象统一做判空处理。
场景二: 然后就是需要去明确一个变量所处特定的作用域范围内可以使用
内联函数:with
它是将某对象作为函数的参数,在函数块内可以通过 this 指代该对象。返回值为函数块的最后一行或指定return表达式。可以看出with函数是接收了两个参数,分别为T类型的对象receiver和一个lambda函数块
class user{
var name = "qing"
var age = 3
var phoneNum = "123"
}
var user = user()
val result = with(user) { //this代表了user,也可以省略this
println("my name is ${this.name}, I am $age years old, my phone number is $phoneNum")
1000 //跟let一样最后一行为返回值(类型也因为最后一行而定)
}
场景:适用于调用同一个类的多个方法时,可以省去类名重复,直接调用类的方法即可,经常用于Android中RecyclerView中onBinderViewHolder中,数据model的属性映射到UI上。
override fun onBindViewHolder(holder: ViewHolder, position: Int){
val item = getItem(position)?: return
with(item){
holder.tvNewsTitle.text = StringUtils.trimToEmpty(titleEn)
holder.tvNewsSummary.text = StringUtils.trimToEmpty(summary)
holder.tvExtraInf.text = "难度:$gradeInfo | 单词数:$length | 读后感: $numReviews"
...
}
}
扩展函数:run
run函数实际上可以说是let和with两个函数的结合体,run函数只接收一个lambda函数为参数,以闭包形式返回,返回值为最后一行的值或者指定的return的表达式。可以说跟with很相似,只是用法不同。
class user{
var name = "qing"
var age = 3
var phoneNum = "123"
}
var user = user()
val run = user?.run {//this代表了user,也可以省略this
println("my name is ${this.name}, I am $age years old, my phone number is $phoneNum")
1000 //跟let一样最后一行为返回值(类型也因为最后一行而定)
}
场景:和with的相同就是用法不同,那看看上面with在onBinderViewHolder使用的时候run怎么去使用
override fun onBindViewHolder(holder: ViewHolder, position: Int){
getItem(position)?.run{ //妥妥的就是let和with的结合体
holder.tvNewsTitle.text = StringUtils.trimToEmpty(titleEn)
holder.tvNewsSummary.text = StringUtils.trimToEmpty(summary)
holder.tvExtraInf = "难度:$gradeInfo | 单词数:$length | 读后感: $numReviews"
...
}
//最为对比把with的也粘贴过来 with
val item = getItem(position)?: return
with(item){
holder.tvNewsTitle.text = StringUtils.trimToEmpty(titleEn)
holder.tvNewsSummary.text = StringUtils.trimToEmpty(summary)
holder.tvExtraInf.text = "难度:$gradeInfo | 单词数:$length | 读后感: $numReviews"
...
}
}
扩展函数:apply
从结构上来看apply函数和run函数很像,唯一不同点就是它们各自返回的值不一样,run函数是以闭包形式返回最后一行代码的值,而apply函数的返回的是传入对象的本身。
//java
mSheetDialogView = View.inflate(activity, R.layout.xxx, null);
mSheetDialogView.textView.text = "123";
mSheetDialogView.buttonView.text = "123";
mSheetDialogView.seek_bar.max = 10;
mSheetDialogView.seek_bar.progress = 0;
}
//使用apply
mSheetDialogView = View.inflate(activity, R.layout.xxx, null).apply{
textView.text = "123" //这里持有的是this = mSheetDialogView 和 run/with一样
buttonView.text = "123"
seek_bar.max = 10
seek_bar.progress = 0 //没有返回值的 他的返回就是传入的本身
}.apply{
//继续
}
场景一:适用于run函数的任何场景,一般用于一个对象实例初始化的时候,需要对对象中的属性进行赋值,XML的View的时候需要给View绑定数据也会用到。
场景二:链式调用使用一个对象时(因为他没有返回值用同一个对象)
场景三:数据model多层级包裹判空处理的问题
扩展函数:also
also函数的结构实际上和let很像唯一的区别就是返回值的不一样,let是以闭包的形式返回,返回函数体内最后一行的值,如果最后一行为空就返回一个Unit类型的默认值。而also函数返回的则是传入对象的本身,他持有的是it对象。
var result = object?.let{//表示object不为null的条件下,才会去执行let函数体
it.todo() //用it代替了object
1000 //最后一行为返回值(所以返回值类型也根据最后一行类型变化)
}?.let{
it.revers() //这里it已经是1000了
2000
}?.let{
it //这里it是2000了
}
var result = object?.let{//表示object不为null的条件下,才会去执行let函数体
it.todo() //用it代替了object
1000 //最后一行为返回值(所以返回值类型也根据最后一行类型变化)
}.also{
it.revers() //这里it还是result
2000
}.also{
it //这里it还是result
}
场景:适用于let函数的任何场景,also函数和let很像,只是唯一的不同点就是let函数最后的返回值是最后一行的返回值而also函数的返回值是返回当前的这个对象。一般可用于多个扩展函数链式调用(因为他没有返回值用同一个对象)
扩展函数:takeIf
理论上你可以把代码中的所有 if 替换成 takeIf(虽然不推荐)
首先takeIf使用如下:
var user = User()
user.takeIf { user.age == 1 }
//如果takeIf中表达式为ture时返回值为this也就是本身
//如果takeIf中表达式为false时返回值为null
那有人问了返回null有什么用,那就需要我们进行配合使用了,比如:
user.takeIf { user.age == 1 } ?: return false
// ?:Elvis操作符: 当前面时null时返回后面的表达式
注意:因为返回时this所以takeIf也可以进行链式调用
user.takeIf { user.age == 1 }?.let{
it
//操作。操作返回的是this = user
//那么这里it是指代的上面的 = user
}
扩展函数:takeUnless
与 takeIf 相反, 如果判断表达式为 true 则返回 null,false 返回对象本身。
循环函数:repeat
repeat() 其实是kotlin中的一个为我们封装好的函数,代表这个括号里面的代码需要被执行多少次,这里我传入了10代表里面的代表需要被循环10次,里面的it为这个函数提供的变量,我们直接使用就可以,他可以显示目前为止程序被执行到了第几次
repeat(10){
print(it);
}