在kotlin中,带接受者的函数字面量这个使用的地方还是很多的,需要仔细理解总结一下
在java中,函数(在java了,把函数称方法)是定义在类里面的,在调用函数的时候,都是先new一个类对象,然后,通过.调用函数。其实调用方法的过程,是把类对象传给了方法,这个也是java常说的一个概念,就是方法有个默认参数是类对象。
在Kotlin中,由于函数是first class(一等公民),类的地位被弱化了,所以好多设计都是围绕函数来的(函数式编程),java是面向对象编程的语言。接受者可以类比于java的类,也是用.操作符的,在实际使用的时候,也是用对象调用方法的,在函数体中,this也是表示调用方法的对象,我理解其实也是给方法传入了一个类对象。把kotlin的这种函数定义叫“扩展函数”
先看一个简单的带接收者的lambda表达式的例子
var subtract : Int.(Int) -> Int = {this - it}
println(3.subtract(2))
这个很好理解,带接收者的lambda表达式也是可以作为函数参数的,这个需要理解一下,我们看看kotlin标准库里面的run方法
/**
* Calls the specified function [block] with `this` value as its receiver and returns its result.
*
* For detailed usage information see the documentation for [scope functions](https://kotlinlang.org/docs/reference/scope-functions.html#run).
*/
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
首先run函数(方法),它自身是带接收者的,接收者类型是T,T是一个范型,就理解成一个具体的类型就行。在run函数的函数体内,我们知道this可以操作这个接收者的,看第一个例子就明白了。然后我们看看run的参数,参数是个函数类型的,不过这里是带接收者的,也就是说在run函数体内是这样使用的:
T类型的接收者实例.block()
在run方法内,this就是一个T类型的接收者实例,this可以省略,所以我们看到是block()这样的调用,这样,block具体代表的函数,其函数体内的this,就是调用run的T类型的接收者实例
好啦,具体细节分析完了,我们抽象出来看,就是:传给run一个函数,函数体内可以访问调用run的实例。看一个例子
val mTvBtn = findViewById<TextView>(R.id.text)
mTvBtn.run{
text = "kotlin"
textSize = 13f
}
这样的代码一看就很简洁呀,也知道这是要干嘛,这个就是给TextView的属性赋值
说明一下:run方法的参数是 () -> R类型的,这个意思就是这个函数没有参数,返回类型是R类型。对有没有参数的函数,lambda表达式中->和->前面的都可以省略掉。而且看这个意思,没有指定具体R类型,说明也是没有的,是没有返回值的。所以我们才看到有上面的代码样子
kotlin的标准库里还提供了不带接收者的run方法,我们也看一下
/**
* Calls the specified function [block] and returns its result.
*
* For detailed usage information see the documentation for [scope functions](https://kotlinlang.org/docs/reference/scope-functions.html#run).
*/
@kotlin.internal.InlineOnly
public inline fun <R> run(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
package com.lzy.learnpro
import android.app.Activity
import android.os.Bundle
import android.widget.TextView
/**
* @Author zhongyili
* @Date 2020/4/7
*/
class SecondActivity: Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val mTvBtn = findViewById<TextView>(R.id.text)
mTvBtn.run{
text = "kotlin"
textSize = 13f
//这个this是mTvBtn
println(this)
}
//这个run方法相当于kotlin类的静态方法
kotlin.run {
mTvBtn.text = "kotlin"
mTvBtn.textSize = 13f
//这个this是SecondActivity
println(this)
}
//这个run的接收者是this,也就是SecondActivity,只是省略掉了
run {
mTvBtn.text = "kotlin"
mTvBtn.textSize = 13f
//这个this是SecondActivity
println(this)
}
}
}
2021年4月19日更新
扩展函数无非就是静态函数的高级语法糖。在kotlin中使用的时候,感觉是一个类的成员函数,其实是个静态函数,在java中使用的方式就是静态函数的形式。扩展函数因为实际是静态函数,所以,是不能重写的。
Kotlin-Extension Functions(扩展函数)实现原理分析
Kotlin——高级篇(二):高阶函数详解与标准的高阶函数使用