-
扩展方法
上图的扩展原型可以等效为如下函数:
fun LastChar(str: String): Char {
return str.get(str.length - 1)
}
需要调用扩展参数也很简单,只需要用参数加点就可以调用,比如我们需要调用图中的扩展函数,如下:
val str="hello"
println( str.LastChar())
其实我在前面的方法进阶的文章中就已经用过扩展,为了加深印象,我们再来实现一个小案例。
案例:实现一个扩展方法,该扩展方法可以交换整型集合的某两个元素的位置。
整体实现如下:
fun main(){
val list= mutableListOf(1,2,3,4)
list.swap(0,3)
println("交换第1个元素和第四个元素后的集合为$list")
}
fun MutableList<Int>.swap(index1:Int,index2:Int){
val temp=this[index1]
this[index1]=this[index2]
this[index2]=temp
}
运行结果:
上面的小案例是为了加深对于扩展方法的应用,在实际开发中swap方法的扩展性也不好,因为他只能交换整型集合元素位置,那如果我们需要交换string类型集合的元素呢?我们可以用泛型对swap方法进行优化,以便他可以交换任意类型集合的元素,改良需要用到泛型方法,不清楚请看我的另一篇文章kotlin-----理解kotlin中的泛型和注解
fun main(){
val list= mutableListOf(1,2,3,4)
list.swap(0,3)
println("交换第1个元素和第四个元素后的集合为$list")
val strlist= mutableListOf("A","B","C")
strlist.swap(0,2)
println("交换第1个元素和第3个元素后的集合为$strlist")
}
fun<T> MutableList<T>.swap(index1:Int,index2:Int){
val temp=this[index1]
this[index1]=this[index2]
this[index2]=temp
}
运行结果:
image.png
经过我们的改良后现在swap方法既可以交换存放Int类型集合元素,也可以对存放其他类型的集合元素进行交换。
-
对类的伴生对象进行扩展
在kotlin中我们可以对类的伴生对象进行扩展,下面是最基本的代码实现
fun main(){
Jump.Print("这是对Jump的伴生对象的扩展方法")
}
class Jump{
companion object{}
}
fun Jump.Companion.Print(str:String){
println(str)
}
在上面代码中我们对类Jump的伴生对象创建了扩展方法Print,值得一提的是我们在调用伴生对象的扩展方法时可以通过伴生对象的类名来直接调用。
-
Kotlin中常用的扩展
在Kotlin的源码中定义了大量的扩展,比如: let ,run,apply ,了 解并运用这些函数能帮我们提高编码效率,下面就一个个地了解下这些函数。
- let扩展
函数原型:
fun <T,R> T.let(f:(T)->R):R=f(this)
let扩展函数的实际上是一个作用域函数,当你需要去定义一个变量在一个特定的作用域范围内,那么let函是一个不错的选择。
如:
fun test(str: String){
str.let {
var str2="hhhh"
}
}
上面代码中变量str2的作用域仅限于let所包裹的括号内,这就是使用let可以限制变量的作用域。
另外let也可以让一些参数避免为null,如下
fun test(str: String){
str.let {
println(it.length)
}
}
上面代码就避免了str为null的情况。关于let大家知道它是个扩展函数并且作用就可以了,关于它的函数原型感兴趣的可以点进去看看他的源码。
- Run扩展
函数原型:
fun <T,R> T.run(f:T.() -> R):R=f()
run函数只接收一个lambda函数为参 数,以闭包形式返回,返回值为最后一行的值或者指定的return的表达式,在run函数中可以直接访问实例的公有属性和方法。
常见用法如下:
//定义一个数据类
data class Room(val price:Int,val name:String,val Num:Int)
fun testRun(room: Room){
//通过run直接访问room的公有属性和方法
room.run {
println("价格:$price,名子:$name 数量:$Num")
}
}
- apply扩展
函数原型:
fun <T> T.apply(f:T.() -> Unit):T{f();return this}
apply函数的作用是:调用某对象的apply函数,在函数范围内,可以任意调用该对象的任意方法,并返回该对象。
从结构上来看apply函数和run函数很像,唯一不同 点就是它们各自返回的值不一样,run函数是以闭包形式返回最后一行代码的值,而apply函数的返回的是传入对象的本身。
apply一般用于一个对象实例初始化的时候,需要对对象中的属性进行赋值。或者动态inflate出一个XML的View的时候需要给View绑定数据也会用到,这种情景非常常见。
我们来实现他的一种使用场景:
比如我们需要创建一个集合,并向里面添加四个元素,然后将集合打印出来。
fun testApply(){
//通过对ArrayList的扩展函数apply直接返回一个集合对象
ArrayList<String>().apply {
add("a")
add("b")
add("c")
add("d")
}.let {
println(it)
}
}
通过代码可以看出,我们使用apply扩展可以直接返回一个ArrayList的对象,都不用创建集合,同时可以对该集合进行添加数据操作。
以上就是kotlin几种常用的扩展函数以及它的常见用途,如果能够在开发中熟练应用对我们的工作有非常大的用处。
-
实战:使用kotlin扩展为控件绑定点击事件
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val testView=find<TextView>(R.id.test)
R.id.test.onclick(this){
testView.text="kotlin扩展"
}
}
//为activity添加扩展方法,用于通过资源id找到控件
fun<T:View> Activity.find(@IdRes id: Int): T {
return findViewById(id)
}
//为资源id添加扩展方法,用于为资源id对应的控件添加点击事件
fun Int.onclick(acticity:Activity,click:()->Unit){
acticity.find<View>(this).apply {
setOnClickListener {
click()
}
}
}
}
里面很多细节值得细细研读,结合lambda表达式、泛型方法和本节内容,这里我就不一一解释,毕竟自己弄懂远比别人说来得好,如果对这段代码实在有困难的可以留言讨论,看到会第一时间回复。
如果你对扩展方法足够熟练,上面代码还可以改成:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val testView=find<TextView>(R.id.test)
testView.onclick{
text="kotlin扩展"
}
}
//为activity添加扩展方法,用于通过资源id找到控件
//@IdRes 注解的作用是知道id为recourse.id的int型
fun<T:View> Activity.find(@IdRes id: Int): T {
return findViewById(id)
}
//为资源id添加扩展方法,用于为资源id对应的控件添加点击事件
fun <T:View> T.onclick(click:T.()->Unit){
setOnClickListener {
click()
}
}
}
网友评论