当前位置: 代码迷 >> 综合 >> kotlin--扩展
  详细解决方案

kotlin--扩展

热度:101   发布时间:2023-09-14 05:46:44.0

之间使用了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.countget() = 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? = nulls.printDefault("123")
}
3.infix

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

infix fun String?.printDefault(default: String) = print(this ?: default)fun main() {val s: String? = nulls 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.randomTakefun main() {println(listOf(4, 7, 9).randomTake())
}
5.重命名扩展

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

import com.aruba.mykotlinapplication.extension.randomTake as randomfun 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关键字