在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)
}
}
}
Kotlin——高級篇(二):高階函數詳解與標準的高階函數使用