之间使用了kotlin的标准函数、匿名函数,觉得它十分灵活,简便。其实kotlin的标准函数就是用了扩展
一、扩展函数
1.定义扩展函数
当我们需要对一个类新增一个方法时,在Java中需要写一个子类继承它,然后添加我们的新方法。
在kotlin中,可以利用扩展增加类的功能,指定类名后就可以新增函数
我们给所有类新增打印函数,给String新增加上!的方法:
//给所有类新增打印函数 :Any.函数名()
fun Any.print() = println(this)
//给String新增加上!的方法
fun String.addExt(count: Int) = this + "!".repeat(count)
fun main() {
"abc".print().print()
}
2.泛型扩展函数
如果想要链式调用我们刚刚新增的函数,先调用下打印,再调用新增!,最后再调用打印是不行的
fun main() {
"abc".print().addExt(5).print()
}
由于print的返回是Any类,但是addExt函数只有String类才有,所以我们需要将print的返回改为String类,但是我又想保持所有类都有print函数,那怎么办呢?
答案是将print函数返回泛型类型,哪个类调用的就返回哪个类
//定义泛型类型扩展函数
fun <T> T.print(): T {
println(this)
return this
}
//给String新增加上!的方法
fun String.addExt(count: Int) = this + "!".repeat(count)
fun main() {
"abc".print().addExt(5).print()
}
结果:
abc
abc!!!!!
泛型扩展函数在标准函数中随处可见,比如let
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
二、扩展属性
1.除了给类扩展函数外,也可以扩展属性
String新增属性,计数元音个数:
//String新增属性,计数元音个数
val String.count
get() = this.count{ "auieoy".contains(it) }
fun main() {
"The people's Republic of China".count.print()
}
2.扩展函数也可以定义于可空类型
可以直接在扩展函数内部处理空的情况
fun String?.printDefault(default: String) = print(this ?: default)
fun main() {
val s: String? = null
s.printDefault("123")
}
3.infix
infix适用于单个入参的扩展函数,可以使语法更简洁,调用方法时的.和()都可以去除
infix fun String?.printDefault(default: String) = print(this ?: default)
fun main() {
val s: String? = null
s printDefault "123"
}
4.扩展文件
为了统一管理,如果想要在多个文件使用扩展函数,可以将它定义在一个单独文件里
定义一个随机函数:
package com.aruba.mykotlinapplication.extension
/**
* Created by aruba on 2021/8/25.
*/
inline fun <T> Iterable<T>.randomTake() = shuffled().first()
别的文件使用import导入:
import com.aruba.mykotlinapplication.extension.randomTake
fun main() {
println(listOf(4, 7, 9).randomTake())
}
5.重命名扩展
可以使用as关键字重命名它的名字
import com.aruba.mykotlinapplication.extension.randomTake as random
fun main() {
println(listOf(4, 7, 9).random())
}
三、DSL
apply函数中,匿名函数中我们可以直接调用接收者的方法,像这种编程范式,业界称为”领域特定语言“,以暴露接收者的函数和特性,以便在lambda中调用和配置它们
apply函数它的实现就是泛型扩展匿名函数
之前我们已经知道如何定义一个匿名函数,现在来定义一个接受匿名函数,返回泛型类型的函数:
fun main() {
println(getInfo { "123" })
}
fun <T> getInfo(funp: () -> T): T {
return funp()
}
现在我们想使getInfo函数中,支持DSL,首先需要getInfo函数支持扩展,并且它入参的匿名函数作用域可以直接使用接收者的函数和属性
1.getInfo函数支持扩展 很简单,直接使用T.getInfo()就可以实现
2.作用域可以直接使用接收者的函数和属性,也是扩展的特性,反观下我们上面写的扩展中,函数里使用的this就是接收者,所以扩展函数中,可以直接使用接收者的函数和属性
想要入参的匿名函数作用域可以直接使用接收者的函数和属性,就需要匿名函数支持扩展:
fun main() {
println("abc".getInfo {
this + "123"
})
}
inline fun <T> T.getInfo(funp: T.() -> T): T {
funp()
return this
}
如果重复使用该方法,将会创建很多内存,所以我们需要使用inline关键字
网友评论