欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Kotlin 高階函數(shù)與Lambda表達(dá)式示例詳解

 更新時間:2022年12月08日 10:22:28   作者:無糖可樂愛好者  
這篇文章主要為大家介紹了Kotlin 高階函數(shù)與Lambda表達(dá)式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

正文

Kotlin中函數(shù)都是頭等的,這意味著它可以存儲在變量與數(shù)據(jù)結(jié)構(gòu)中、作為參數(shù)傳遞給其他高階函數(shù)以及從其他高階函數(shù)返回??梢韵虿僮魅魏纹渌呛瘮?shù)值一樣操作函數(shù)。

為促成這點,作為一門靜態(tài)類型編程語言的Kotlin使用一系列函數(shù)類型來表示函數(shù)并提供了一組專門的語言結(jié)構(gòu),例如Lambda表達(dá)式。

這段話來自Kotlin文檔。從沒有接觸過Kotlin的話這段話的意思很難理解,上面有三個關(guān)鍵詞【高階函數(shù)】、【函數(shù)類型】、【Lambda表達(dá)式】先分析這三個關(guān)鍵詞然后再對上面這段話進(jìn)行理解。

1.函數(shù)類型

函數(shù)類型就是函數(shù)的類型, 變量有類型Int、String等,那函數(shù)的類型到底是指什么?

fun lastElement(str: String): Char {
    return str[str.length - 1]
}

上面的代碼是之前用過的,意思是獲取字符串的最后一個字符,其中參數(shù)類型是String,返回值類型是Char,將其抽出來就是【String -> Char】這就代表了函數(shù)的類型,一句話概括就是:將函數(shù)的【參數(shù)類型】和【返回值類型】抽象出來就得到了函數(shù)的【函數(shù)類型】。【(String) -> Char】的意思就是參數(shù)類型是【String】,返回值類型是【Char】的函數(shù)類型。這個比較好理解。類似的還有Kotlin中繼承自BaseAdapter的幾個方法

//函數(shù)類型:() -> Int
override fun getCount(): Int {
}
//函數(shù)類型:(Int) -> Any
override fun getItem(position: Int): Any {
}
//函數(shù)類型:(Int) -> Long
override fun getItemId(position: Int): Long {
}

2.高階函數(shù)

理解餓了函數(shù)類型再來看下高階函數(shù)。

高階函數(shù)是將函數(shù)用作參數(shù)或返回值的函數(shù), 這是高階函數(shù)的定義。

  • 函數(shù)用作參數(shù)的高階函數(shù)寫法
fun main() {
    val result = answer(20) { 10 }
    println("result:$result")       //輸出結(jié)果:result:30
}
/**
 * 高階函數(shù)
 * 函數(shù)類型:(Int, add方法) -> Int
 */
fun answer(num: Int, add: () -> Int): Int {
    return num + add()
}

上面的代碼用的是高階函數(shù)中的函數(shù)用作參數(shù)的寫法,定義一個answer方法,添加一個參數(shù)num和函數(shù)add,因為add方法返回值是一個Int類型因此可以跟num直接相加并返回結(jié)果,代碼沒有實際意義就是個例子。

這里可能會產(chǎn)生一個疑問:為什么result的調(diào)用方式是成立的?

將上面的代碼轉(zhuǎn)換成Java的寫法就清楚了

public final class HighFunctionKt {
   public static final void main() {
      int result = answer(20, (Function0)null.INSTANCE);
      String var1 = "result:" + result;
      boolean var2 = false;
      System.out.println(var1);
   }
   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }
   public static final int answer(int num, @NotNull Function0 add) {
      Intrinsics.checkNotNullParameter(add, "add");
      return num + ((Number)add.invoke()).intValue();
   }
}

可以看到add方法被轉(zhuǎn)換成了Function0,并且num與add方法的返回值進(jìn)行了相加,那么這里有一個新的疑問invoke是什么?invokeFunction0的一個方法,作用就是調(diào)用函數(shù),在Functions.kt類中,Function的數(shù)量達(dá)到Function21,從Function0Function21的區(qū)別就是傳參數(shù)量的不同。

public interface Function0<out R> : Function<R> {
    /** Invokes the function. */
    public operator fun invoke(): R
}

再來看一個稍微復(fù)雜的高階函數(shù)例子,answer函數(shù)中又添加了一個參數(shù),同時函數(shù)參數(shù)也支持傳參

fun main() {
    val add = answer(10, 20) { num1, num2 -> num1 + num2 }
    val minus = answer(10, 20) { num1, num2 -> num1 - num2 }
    println("add:$add")       //輸出結(jié)果:result:30
    println("minus:$minus")       //輸出結(jié)果:result:30
}
fun answer(num1: Int, num2: Int, result: (Int, Int) -> Int): Int {
    return result(num1, num2)
}

answer方法做了改動,傳了兩個參數(shù),函數(shù)類型的參數(shù)也傳入了兩個參數(shù),這樣定義的作用是更靈活

  • 函數(shù)用作返回值的高階函數(shù)寫法
fun main() {
    println(answer(10).invoke())	//輸出結(jié)果:輸入的數(shù):10
}
fun answer(num: Int): () -> String {
    return { "輸入的數(shù):${num}" }
}

這里的invoke就是一個調(diào)用函數(shù)的功能。編譯成Java代碼如下所示:

public final class HighFunctionKt {
    public static final void main() {
        Object var0 = answer(10).invoke();
        boolean var1 = false;
        System.out.println(var0);
    }
    // $FF: synthetic method
    public static void main(String[] var0) {
        main();
    }
    @NotNull
    public static final Function0 answer(final int num) {
        return (Function0)(new Function0() {
            // $FF: synthetic method
            // $FF: bridge method
            public Object invoke() {
                return this.invoke();
            }
            @NotNull
            public final String invoke() {
                return "輸入的數(shù):" + num;
            }
        });
    }
}
  • 應(yīng)用場景舉例

Android開發(fā)過程中RecycleView是常用的一個組件,但是它本身不支持點擊事件,現(xiàn)在,假設(shè)我們在Adapter中有兩個點擊事件,添加和刪除,常用的寫法會先定義一個接口,對該接口定義一個變量,然后定義一個方法,代碼如下:

private lateinit var mOnItemAddClickListener: OnItemAddClickListener
private lateinit var mOnItemDeleteClickListener: OnItemDeleteClickListener
interface OnItemAddClickListener {
    fun onItemAddClick(position: Int)
}
interface OnItemDeleteClickListener {
    fun onItemDeleteClick(position: Int)
}
fun setOnItemAddClickListener(onItemAddClickListener: OnItemAddClickListener) {
    mOnItemAddClickListener = onItemAddClickListener
}
fun setOnItemDeleteClickListener(onItemDeleteClickListener: OnItemDeleteClickListener) {
    mOnItemDeleteClickListener = onItemDeleteClickListener
}
holder.ivAdd.setOnClickListener {
    mOnItemAddClickListener.onItemAddClick(position)
}
holder.ivDelete.setOnClickListener {
    mOnItemDeleteClickListener.onItemDeleteClick(position)
}
adapter.setOnItemAddClickListener(object :DemoAdapter.OnItemAddClickListener{
    override fun onItemAddClick(position: Int) {
        TODO("Not yet implemented")
    }
})
adapter.setOnItemDeleteClickListener(object :DemoAdapter.OnItemDeleteClickListener{
    override fun onItemDeleteClick(position: Int) {
        TODO("Not yet implemented")
    }
})

用高階函數(shù)對其進(jìn)行優(yōu)化后的代碼如下:

private lateinit var mOnItemAddClickListener: (Int) -> Unit
private lateinit var mOnItemDeleteClickListener: (Int) -> Unit
fun setOnItemAddClickListener(listener: (Int) -> Unit) {
    mOnItemAddClickListener = listener
}
fun setOnItemDeleteClickListener(listener: (Int) -> Unit) {
    mOnItemDeleteClickListener = listener
}
holder.ivAdd.setOnClickListener {
    mOnItemAddClickListener.invoke(position)
}
holder.ivDelete.setOnClickListener {
    mOnItemDeleteClickListener.invoke(position)
}
adapter.setOnItemAddClickListener {
}
adapter.setOnItemDeleteClickListener {
}

這兩種寫法的代碼進(jìn)行對比可以發(fā)現(xiàn)高階函數(shù)的實現(xiàn)方式中沒有定義接口,同時它代碼量顯著減少,代碼也變得更加簡潔。

3.系統(tǒng)標(biāo)準(zhǔn)高階函數(shù)

系統(tǒng)的標(biāo)準(zhǔn)高階函數(shù)來自Standard.kt,里面的方法也是比較常用的

  • run
public inline fun <R> run(block: () -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

block是函數(shù)式參數(shù)的名稱,傳入的函數(shù)類型是()-> RR是泛型

這段代碼的意思就是調(diào)用傳入的函數(shù)并返回結(jié)果,return block()就是傳入函數(shù)的調(diào)用。

怎么用?or有什么用?

fun main() {
    run { println(add(1, 2)) }
}
fun add(num1: Int, num2: Int): Int {
    return num1 + num2
}

作用就是構(gòu)建Lambda更方便

  • T.run
public inline fun <T, R> T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

這個run更上面那個的區(qū)別在于它有一個接收者,有了這個接收者就可以使用上下文了,例如:

val num = 10
num.run { println("result:${this + 1}") }	//輸出結(jié)果:result:11

還有一種情況,例如要從某個對象中取出它的一些屬性的值也可以通過T.run,同時由于可以將this省略因此代碼就可以這么寫:

class Person(val name:String, var age:Int)
val person = Person("張三", 19)
person.run{
    println("name:$name")
    println("age:$age")
}

再舉個例子,TextView利用T.run修改屬性并賦值

holder.tvText.run {
    text = "自定義文本"
    setTextColor(context.getColor(R.color.color_000000))
    textSize = 20F
}
  • whith
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}

with的使用方式與T.run類似,with在返回值上帶了一個接收者,看下面代碼

with(holder.tvText) {
    text = "自定義文本"
    setTextColor(context.getColor(R.color.color_000000))
    textSize = 20F
}
  • T.apply
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

這個函數(shù)的意思就是接收者傳入了什么返回值就是什么,使用案例:

val person = Person("張三", 19)
person.apply {
    println("name:$name")			//輸出結(jié)果:張三
    println("age:$age")				//輸出結(jié)果:19
}.age = 10					   		//把張三的年齡修改我10歲
println("name:${person.name}")		//輸出結(jié)果:張三
println("age:${person.age}")		//輸出結(jié)果:10

有什么用?

Android中會遇到根據(jù)狀態(tài)修改Button樣式然后還要響應(yīng)點擊事件的情況,常用寫法就不在這里講了,這里用T.apply實現(xiàn):

button.apply {
    text = "提交"
    setTextColor(context.getColor(R.color.color_000000))
    background = context.getDrawable(R.drawable.shape_solid_4dp_4e6cf5)
}.setOnClickListener { 
    //點擊事件
}

這行代碼是不是很簡潔。

還有webview的使用

webView.apply {
    settings.javaScriptEnabled = true
    settings.useWideViewPort = true
}.loadUrl("https://www.baidu.com/")

T.apply很靈活,具體問題具體分析就好。

  • T.also
public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}

T.also的意思就是用傳參調(diào)用指定函數(shù)并返回這個參數(shù)

button.also {
    it.text
}

這里的button在調(diào)用also之后在它的里面只能用it也必須用it,這個it指的是button本身,而T.apply中是this指的是Button本身,并且這個this是可以被省略的。使用過程中的區(qū)別不大。

  • T.let
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}

T.let的意思就是使用傳參調(diào)用指定函數(shù)然后返回結(jié)果,代碼如下

val person = Person("張三", 19)
val str = "Hello Kotlin"
val result = person.let {
    it.name == "張三"
}
println("result:$result")		//輸出結(jié)果:result:true
println("length:${str.let { it.length }}")	//輸出結(jié)果:length:12

在Person類中有一個name = 張三的實例,經(jīng)過let判斷后返回true;獲取str字符串的長度得到最終結(jié)果12。

  • T.takeIf
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
    contract {
        callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
    }
    return if (predicate(this)) this else null
}

T.takeIf的意思就是如果符合條件則返回傳入的值,否則返回null

val person = Person("張三", 19)
val result = person.takeIf {
    it.name == "李四"
}
println("result:${result?.name}")		//輸出結(jié)果:result:null
val result = person.takeIf {
    it.name == "張三"
}										//條件成立返回person對象
  • T.takeUnless
public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? {
    contract {
        callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
    }
    return if (!predicate(this)) this else null
}

T.takeUnlessT.takeIf正好相反,如果滿足條件則返回null,不滿足則返回正確的謂詞

val person = Person("張三", 19)
val result = person.takeUnless {
    it.name == "李四"
}
println("result:${result?.name}")		//輸出結(jié)果:result:張三
val result = person.takeUnless {
    it.name == "張三"
}
println("result:${result?.name}")		//輸出結(jié)果:result:null
  • repeat
public inline fun repeat(times: Int, action: (Int) -> Unit) {
    contract { callsInPlace(action) }
    for (index in 0 until times) {
        action(index)
    }
}

action函數(shù)就是一個重復(fù)執(zhí)行的函數(shù),從0開始

repeat(2) {
    println("執(zhí)行第:${it}次")
}
//輸出結(jié)果:
//執(zhí)行第:0次
//執(zhí)行第:1次

4.Lambda表達(dá)式

Lambda表達(dá)式在Java中已經(jīng)用的比較多了,通過它可以簡化代碼和提高開發(fā)效率,所以我們可以把Lambda表達(dá)式理解為函數(shù)的簡寫。

例如view的點擊事件在Kotlin中調(diào)用時就是這樣的:

fun setOnClickListener(l: ((View!) -> Unit)?){
}
//調(diào)用時可以這么寫:
button.setOnClickListener{
}

開頭提出了一個結(jié)論:在Kotlin中函數(shù)是頭等的,為什么這么說呢?

  • Kotlin的函數(shù)可以獨立于類之外,這就是頂層函數(shù)
  • Kotlin的函數(shù)可以作為參數(shù)也可以作為函數(shù),它被稱為高階函數(shù)和Lambda
  • Kotlin的函數(shù)可以向變量一樣,這叫做函數(shù)引用

以上就是Kotlin 高階函數(shù)與Lambda表達(dá)式示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Kotlin 高階函數(shù)Lambda的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Android實現(xiàn)登錄注冊界面框架

    Android實現(xiàn)登錄注冊界面框架

    這篇文章主要介紹了Android實現(xiàn)登錄注冊界面的框架,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • Android編程之Activity中onDestroy()調(diào)用分析

    Android編程之Activity中onDestroy()調(diào)用分析

    這篇文章主要介紹了Android編程之Activity中onDestroy()調(diào)用方法,針對onDestroy引起的內(nèi)存泄露及解決方法進(jìn)行了分析,并給出了解決方案,需要的朋友可以參考下
    2015-12-12
  • 進(jìn)度條ProgressBar及ProgressDialog(實例)

    進(jìn)度條ProgressBar及ProgressDialog(實例)

    下面小編就為大家?guī)硪黄M(jìn)度條ProgressBar及ProgressDialog(實例)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07
  • 基于Fedora14下自帶jdk1.6版本 安裝jdk1.7不識別的解決方法

    基于Fedora14下自帶jdk1.6版本 安裝jdk1.7不識別的解決方法

    本篇文章是對Fedora14下自帶jdk1.6版本,安裝jdk1.7不識別的解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • Android自定義控件實現(xiàn)簡單滑動開關(guān)效果

    Android自定義控件實現(xiàn)簡單滑動開關(guān)效果

    這篇文章主要為大家詳細(xì)介紹了Android自定義控件實現(xiàn)簡單滑動開關(guān)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • Android讀取XML文件中的數(shù)據(jù)

    Android讀取XML文件中的數(shù)據(jù)

    這篇文章主要為大家詳細(xì)介紹了Android讀取XML文件中的數(shù)據(jù),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • Android高效安全加載圖片的方法詳解

    Android高效安全加載圖片的方法詳解

    Android開發(fā)中消耗內(nèi)存較多一般都是在圖像上面,下面這篇文章主要給大家介紹了關(guān)于Android如何高效安全加載圖片的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • Android scrollview實現(xiàn)底部繼續(xù)拖動查看圖文詳情

    Android scrollview實現(xiàn)底部繼續(xù)拖動查看圖文詳情

    這篇文章主要為大家詳細(xì)介紹了Android scrollview實現(xiàn)底部繼續(xù)拖動查看圖文詳情,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-02-02
  • Android視圖綁定方法深入探究

    Android視圖綁定方法深入探究

    這篇文章主要介紹了Android視圖綁定方法,通過視圖綁定viewBinding功能,您可以更輕松地編寫可與視圖交互的代碼。在模塊中啟用視圖綁定之后,系統(tǒng)會為該模塊中的每個XML
    2023-01-01
  • 如何在android中制作一個方向輪盤詳解

    如何在android中制作一個方向輪盤詳解

    這篇文章主要給大家介紹了關(guān)于如何在android中制作一個方向輪盤的相關(guān)資料,這個是在手游領(lǐng)域中很常見的用于控制方向的輪盤,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-09-09

最新評論