kotlin--扩展

2021-12-06 17:19:39 浏览数 (1)

之间使用了kotlin的标准函数、匿名函数,觉得它十分灵活,简便。其实kotlin的标准函数就是用了扩展
一、扩展函数
1.定义扩展函数

当我们需要对一个类新增一个方法时,在Java中需要写一个子类继承它,然后添加我们的新方法。 在kotlin中,可以利用扩展增加类的功能,指定类名后就可以新增函数 我们给所有类新增打印函数,给String新增加上!的方法:

代码语言:javascript复制
//给所有类新增打印函数 :Any.函数名()
fun Any.print() = println(this)

//给String新增加上!的方法
fun String.addExt(count: Int) = this   "!".repeat(count)

fun main() {
    "abc".print().print()
}
2.泛型扩展函数

如果想要链式调用我们刚刚新增的函数,先调用下打印,再调用新增!,最后再调用打印是不行的

代码语言:javascript复制
fun main() {
    "abc".print().addExt(5).print()
}

由于print的返回是Any类,但是addExt函数只有String类才有,所以我们需要将print的返回改为String类,但是我又想保持所有类都有print函数,那怎么办呢? 答案是将print函数返回泛型类型,哪个类调用的就返回哪个类

代码语言:javascript复制
//定义泛型类型扩展函数
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

代码语言:javascript复制
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}
二、扩展属性
1.除了给类扩展函数外,也可以扩展属性

String新增属性,计数元音个数:

代码语言:javascript复制
//String新增属性,计数元音个数
val String.count
    get() = this.count{ "auieoy".contains(it) }

fun main() {
    "The people's Republic of China".count.print()
}
2.扩展函数也可以定义于可空类型

可以直接在扩展函数内部处理空的情况

代码语言:javascript复制
fun String?.printDefault(default: String) = print(this ?: default)

fun main() {
    val s: String? = null
    s.printDefault("123")
}
3.infix

infix适用于单个入参的扩展函数,可以使语法更简洁,调用方法时的.和()都可以去除

代码语言:javascript复制
infix fun String?.printDefault(default: String) = print(this ?: default)

fun main() {
    val s: String? = null
    s printDefault "123"
}
4.扩展文件

为了统一管理,如果想要在多个文件使用扩展函数,可以将它定义在一个单独文件里 定义一个随机函数:

代码语言:javascript复制
package com.aruba.mykotlinapplication.extension

/**

 * Created by aruba on 2021/8/25.

 */
inline fun <T> Iterable<T>.randomTake() = shuffled().first()

别的文件使用import导入:

代码语言:javascript复制
import com.aruba.mykotlinapplication.extension.randomTake

fun main() {
    println(listOf(4, 7, 9).randomTake())
}
5.重命名扩展

可以使用as关键字重命名它的名字

代码语言:javascript复制
import com.aruba.mykotlinapplication.extension.randomTake as random

fun main() {
    println(listOf(4, 7, 9).random())
}
三、DSL
apply函数中,匿名函数中我们可以直接调用接收者的方法,像这种编程范式,业界称为”领域特定语言“,以暴露接收者的函数和特性,以便在lambda中调用和配置它们

apply函数它的实现就是泛型扩展匿名函数 之前我们已经知道如何定义一个匿名函数,现在来定义一个接受匿名函数,返回泛型类型的函数:

代码语言:javascript复制
fun main() {
    println(getInfo { "123" })
}

fun <T> getInfo(funp: () -> T): T {
    return funp()
}

现在我们想使getInfo函数中,支持DSL,首先需要getInfo函数支持扩展,并且它入参的匿名函数作用域可以直接使用接收者的函数和属性 1.getInfo函数支持扩展 很简单,直接使用T.getInfo()就可以实现 2.作用域可以直接使用接收者的函数和属性,也是扩展的特性,反观下我们上面写的扩展中,函数里使用的this就是接收者,所以扩展函数中,可以直接使用接收者的函数和属性 想要入参的匿名函数作用域可以直接使用接收者的函数和属性,就需要匿名函数支持扩展:

代码语言:javascript复制
fun main() {
    println("abc".getInfo {
        this   "123"
    })
}

inline fun <T> T.getInfo(funp: T.() -> T): T {
    funp()
    return this
}

如果重复使用该方法,将会创建很多内存,所以我们需要使用inline关键字

0 人点赞