Kotlin Lambda和高階函數

Lambda和高階函數

本文鏈接:

文章目錄

    • Lambda和高階函數
  • lambda
    • 輸出(返回類型)
    • 深入探究
      • 泛型
    • inline原理探究
  • 高階函數
    • 集合、泛型
    • 自己實現Kotlin內置函數
  • 擴展函數原理
  • companion object 原理 ==> 靜態內部類
  • 函數式編程

lambda

1、lambda的由來

  1. 單詞"lambda"源于希臘字母λ(小寫lambda)
  2. "Lambda"一詞最早起源于數學中的λ演算(lambda calculus),它是一種函數定義和函數應用的形式系統,由邏輯學家阿隆佐·邱奇(Alonzo Church)在20世紀30年代發明。
  3. 邱奇使用λ作為演算中的一個操作符,用于表示匿名函數。他選擇使用希臘字母λ的原因是因為它在字母表中的位置不太常見,這樣可以避免與其他符號混淆。

2、函數的聲明

    // 函數的聲明val method01:()->Unitval method02:(Int, Int)->Unitval method03:(String, Double)->Any // 相當于Objectval method04:(String, Double, Float)->Boolean

3、kotlin中Any和Java的Object有什么區別嗎?

  1. Any是所有非空類型的超類型,類似于Java中的Object。Object不能持有null。
  2. Any?是所有類型的超類型,包括可空類型。
    Any?可以持有null值

4、函數如何調用/函數的實現(lambda)?invoke是什么?

// 函數變量通過invoke()調用
// ()是運算符重載
// 函數的實現
val method01:()->Unit
method01 = { println("我實現了method01") }
method01() // 調用函數:操作符重載
method01.invoke() // 調用函數:真實方法// 方法三的實現
val method03:(String, Double)->Any // 相當于Object
method03 = {name, number ->println("$name $number")name + number
}
println(method03("wch", 1234567.89))

5、函數的實現(傳入函數)

val method04:(String, Double, Float)->Boolean= fun(name:String, number:Double, age:Float):Boolean = (name+number+age).isEmpty()
method04("wch", 376.23, 1234.5f)

6、單一參數的lambda默認持有it ===> 函數式接口 ===> SAM

    val method05:(Int)->Unit = {print("$it")}

7、下劃線可以拒收 ===> 拒收

    val method06:(Int, Int)->Unit = { _, number->println("$number")}

8、作用是什么?

  1. 節省空間
  2. 接口版本變化,有的參數沒用了

9、想要允許參數為null,需要用可空類型如String?

val method07:(String?,String)->Unit = {sex, name -> println("$sex,$name")}method07(null, "wch")

10、Lambda不可以使用泛型作為參數類型
11、Lambda參數不可以給默認值 ===> 默認參數
12、Lambda Any->Any

    // 傳入什么,打印什么,還可以返回任何東西val method18:(Any)->Any={println("$it")it // 還可以返回自己}

13、Lambda配合擴展方法 ===> 擴展方法 ===> 官網寫的Funciton,但是接收receiver

    val method19: String.()->Unit = {// this = String本身 == 調用者本身println("你是$this")}"WCH".method19()

14、為什么method19可以成為String的擴展方法?

  1. 代碼val method19: String.()->Unit = { ... }表示定義了一個接收者類型為String的擴展函數類型。
  2. String.()->Unit表示該函數類型接收一個String作為接收者,并返回Unit類型(即沒有返回值)。
  3. 進一步理解:==> 匿名擴展函數
val method18: ()->Unit; // 類型是 函數
val method19: String.()->Unit // 類型是 String的擴展函數
val method20: (String)->Unit // 類型是 函數,該函數的參數是String

15、進一步融合this和it,區分擴展函數 和 參數的區別

val method20: Int.(Int) -> String = {"兩數相加的結果:${this+it}"}
println(1.method20(10))println(method20(1, 10)) // 1, 可以自動插為第一個參數

函數的形式:

fun Int.method21(n:Int):String{return "兩數相加的結果:${this+n}"
}
println(2.method21(22))
// println(method21(2, 22)) // 不可以這樣寫了

輸出(返回類型)

1、Lambda的返回類型:函數

    /**============================* 函數*============================*/// 默認Unitfun t01(){ println() }// 默認Unitfun t02(){4652342.5f}// 默認Unitfun t03(){"Hello!"}// String:顯式指明返回值fun t04():String{return "feather"} // return 還不支持自動推斷類型

2、函數返回函數

    /**==============================* 函數返回函數*=============================*/// ()->Unitfun s01() = {}fun s02() = { println("Haha") }s02()() // 輸出// Booleanfun s03() = run{ true }// 返回的是代碼塊的最后一行s03()// ()->Stringfun s04():()->String = {"Hello"}println(s04()) // Function0<java.lang.String>println(s04()())

3、Java中Lambda是假的

深入探究

4、Lambda深入探究

    // k01()返回的類型是: (Int)->Unitfun k01() = {n:Int -> println(n) }k01()(123)// lambda使用,第一種用的多val methodx2 = {str:String -> str.length}val methodx2s:(String)->Int = {it.length}

5、Kotlin的Lambda如何和Java兼容?源碼機制

  1. kotlin編譯器實現(很強大) -> JVM字節碼
  2. package kotlin.jvm.functions中定義了Function系列
  3. 最多Funciton22,高版本編譯器可以處理>22個參數的情況,低版本會出錯
// val methodx2 = {str:String -> str.length}
Function1 methodx2 = (Function1)null.INSTANCE;
// (String)->Unit
val method3:Function1<String, Unit> = { println(it) }

6、Lambda考題

    //(Int,Int) -> (Int,Int) ->Stringval funX10 = fun(n1:Int,n2:Int):(Int,Int)->String={n1,n2 -> "兩個數相加:${n1 + n2}"}println(funX10(10, 10)(20, 20))// 迷惑點,最外層的n1和n2和內層的n1 n2沒關系
// 函數的函數的函數的函數val k01: (String) -> (Boolean) -> (Int) -> (Float) -> Double ={ it ->{ it ->{ it ->{ it ->123.456}}}}println(k01("AAA")(true)(45)(67.89f))

7、下面的study02()返回的類型是什么?

fun study02() = {lambda:(Int, Int) -> String, studyInfo: String ->lambda(1, 99)
}
// 答案:((Int, Int) -> String, String) -> Unit // 使用:
study02()({n1, n2-> "$n1 + $n2 = ${n1 + n2}" }, "wch")

8、下面study04()返回的類型是什么?

fun study04() = {str:String, num:Int, lambda1:(String)->Unit, lambda2:(Int)->Boolean->lambda1(str)lambda2(num)
}
// 答案:(String,Int,(String)->Unit,(Int)->Unit)->Boolean// 使用:
println(study04()("wch", 123, { println("$it lambda1") }, { it > 99}))

泛型

9、下面返回的類型是什么?

fun <T1, T2, R1, R2> study05() = {str:T1, num:T2, lambda1:(T1)->R1, lambda2:(T2)->R2 ->lambda1(str)lambda2(num)
}
// (T1, T2, (T1)->R1, (T2)->R2) -> R2// 使用:
study05<String, Int, Boolean, Float>()("wch", 22, {it.isEmpty()}, {it.toFloat()})

10、下面的study06不是lambda,是函數。他們的類型是什么?

fun study05() = {Str:String, num: Int, lambda:(Int)->Boolean ->lambda(num)
}
// (String, Int, (Int)->Boolean)->Booleanfun study06() = fun(Str:String, num: Int, lambda:(Int)->Boolean):Boolean{return lambda(num)
}
// (String, Int, (Int)->Boolean)->Boolean
  1. Lambda表達式,最后一行作為返回值
  2. 函數,最后一行不能作為返回值
  3. 必須顯式return
  4. 必須顯式指定

函數有隱式的Unit類型返回值

inline原理探究

1、Lambda為什么要內聯?

  1. 不使用內聯,會構造出Function0對象,作為參數傳入
  2. 代碼內聯,減少方法調用開銷,不再需要創建Function0對象 ===> 內存抖動
fun main() {show{println("Hello Kotlin!")}
}
fun show(lambda:()->Unit){lambda()
}
// 不使用內聯生成代碼:
show((Function0)null.INSTANCE);
public static final void show(@NotNull Function0 lambda) {Intrinsics.checkNotNullParameter(lambda, "lambda");lambda.invoke();
}
// 使用內聯:
int $i$f$show = false;
int var1 = false;
String var2 = "Hello Kotlin!";
System.out.println(var2);

高階函數

===> Compose內部實現,學習

1、高階函數是什么?高階函數 = lambda + 函數

fun a() {}
val a1 = {} // 函數引用,接收,匿名函數
val a2 = a1 // 函數引用
val a3 = ::a // 將函數變成函數引用

2、高階函數就是函數的函數,函數中有lambda

// Lambda開胃菜// 返回Stringfun show01(number:Int, lambda:(Int)->String) = lambda.invoke(number)// 調用函數var r01 = show01(99){it.toString()}// return Intfun show02(n1:Int,n2:Int,n3:Int, lambda: (Int,Int,Int)->Int) = lambda(n1, n2, n3)show02(10, 20, 30){i, i2, i3 ->i + i2 + i3}

3、高階函數例子

// 第一版,高階函數應用
fun main() {loginEngine("wch", "123456")
}private fun loginEngine(name:String, pwd:String){loginServer(name, pwd){code, msg->print("錯誤碼$code 錯誤信息$msg")}
}private fun loginServer(name:String, pwd:String, lambda:(Int, String)->Unit){if(name.isEmpty() || pwd.isEmpty()){lambda(-1, "Empty")return}lambda(1, "Success")
}
// 第二版

4、高階函數

// (一)給泛型增加匿名擴展函數
fun<T> T.myRun01(block: T.(Float) -> Boolean) = block(123.45f)
// this = T本身 = 調用者本身 == Derry// 使用
"Derry".myRun01 {isEmpty()
}// (二)
fun<T> T.derry4(number:Double, mm: T.(Double) -> Unit){mm(number)
}
"Derry".derry4(123.456){// this = 調用者println(this)
}// (三)
fun<T> T.myRunPlus(block: T.(T, T) -> Boolean) = block(this,this)

5、T.() -> Boolean s是什么意思?

  1. 對T擴展出匿名函數
  2. 匿名函數是 ()->Boolean
  3. 該匿名擴展函數只有這個高階函數可以使用,其他地方用不出來

6、多個lambda調用

// (一)
show2(lambda1 = {}, lambda2 = {})
//(二)
show2({}, {})
// (三)
show2({println("Hello")}){println("World!")
}

7、源碼使用高階函數,利用函數引用

show(::lambdaImpl)fun lambdaImpl(){println("HAHA")
}// 函數引用場景
fun lambdaImpl(name:String):Unit{println(name)
}
var r1:Function1<String, Unit> = ::lambdaImpl
var r2:(String)->Unit = ::lambdaImpl
var r3:String.()->Unit = ::lambdaImpl // (String)等價于String.()

集合、泛型

1、Lambda+集合+泛型

class AndroidClickListener<T>{// 1. 集合的元素類型是Lambda,并且Lambda輸入參數的類型是 Tval actions = arrayListOf<(T)->Unit>()val actions2 = arrayListOf<(T?)->Unit>() // 可空// 2. 集合的元素類型為泛型val values = arrayListOf<T?>()// 3、設置監聽fun addListener(value:T?, lambda:(T?)->Unit){values += value // 運算符重載actions2 += lambda}// 4、通知觀察者fun notify(value:T?){val index = values.indexOf(value)actions2[index].invoke(value) // 執行方法actions2[index](value) // 執行方法二}// 5. 模擬點擊事件,通知所有觀察者fun touchListeners(){actions2.forEachIndexed{index, function ->  function(values[index])}}
}// 使用,測試val click = AndroidClickListener<String>()click.addListener("HaHa"){println("接收到數據:$it")}click.addListener("WCH"){println("$it 在吃飯中...")}click.addListener("Feather"){println("百萬博客主:$it")}click.touchListeners()// 函數引用版本fun method(value:String?){println(value)}click.addListener("Hello", ::method)

2、如何用變量接收類型中包含泛型的函數?

fun<T> method(value: T?):Unit{println(value)
}// 不可以用泛型
//    val error:(T?)->Unit = ::method// Any來代表T?val m1:(Any)->Unit = ::methodm1("Hello")// 具體類型也可以val m2:(Int)->Unit = ::methodm2(123)

自己實現Kotlin內置函數

1、forEach

// 定義
inline fun<E> Iterable<E>.mForEach(lambda:(E)->Unit){for(item in this)lambda(item)
}// 使用
listOf("AAA", "BBB", "CCC").mForEach{println(it)}

2、let和run,為什么會有this,為什么會有it

  1. this,it
  2. T.()->R, this是對T的匿名擴展函數,擁有this
  3. (T)->R,it是參數類型,SAM單一抽象接口,函數式接口,it
public inline fun <T, R> T.run(block: T.() -> R): R {return block()
}
public inline fun <T, R> T.let(block: (T) -> R): R {return block(this)
}

3、thread

  1. 注意點: corssinline
// 自己實現thread,特定lambda不能inline
inline fun thread(start:Boolean = true,name:String?=null,crossinline runAction:()->Unit // 限制不能inline,會copy大量代碼
):Thread{val thread = object:Thread(){override fun run() {super.run()runAction()}}if(start) thread.start() // name?.let { thread.name = it } // kotlin形式return thread
}

擴展函數原理

1、擴展函數就是構造static final方法,將對象作為返回值

class MyKt {}
fun MyKt.show() = println(this)
public final class MyKt {}
// 構造出Kt類,添加擴展函數名一樣的static final方法,將類的對象作為參數
public final class MyKtKt {public static final void show(@NotNull MyKt $this$show) {Intrinsics.checkNotNullParameter($this$show, "$this$show");System.out.println($this$show);}
}

2、思考:叫做擴展函數是否是因為沒有receiver?

companion object 原理 ==> 靜態內部類

1、為什么叫伴生對象?

  1. 生成靜態內部類
  2. 生成靜態成員變量(類變量)
  3. 通過伴生對象實例,調用方法和獲取字段

2、使用處

class MyKt {companion object{fun show(){println(this)}val name = "wch"}
}fun main() {MyKt.show()MyKt.name
}

3、反編譯,生成源碼

  1. 生成靜態內部類,Companion,并且有show()方法和字段name
  2. 類中Companion實例,是static final變量
  3. 像Java一樣調用類方法和獲取類屬性,本質通過Companion伴生對象,調用方法和get字段
public final class MyKt {private static final String name = "wch";public static final Companion Companion = new Companion((DefaultConstructorMarker)null);public static final class Companion {public final void show() {System.out.println(this);}public final String getName() {return MyKt.name;}private Companion() {}// $FF: synthetic methodpublic Companion(DefaultConstructorMarker $constructor_marker) {this();}}
}// 使用處
MyKt.Companion.show();
MyKt.Companion.getName();

函數式編程

Kotlin函數式編程

  1. 鏈式調用
  2. 非常豐富的函數庫
  3. 模仿RxJava的響應式編程

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/42167.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/42167.shtml
英文地址,請注明出處:http://en.pswp.cn/news/42167.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Flink流批一體計算(13):PyFlink Tabel API之SQL DDL

1. TableEnvironment 創建 TableEnvironment from pyflink.table import Environmentsettings, TableEnvironment# create a streaming TableEnvironmentenv_settings Environmentsettings.in_streaming_mode()table_env TableEnvironment.create(env_settings)# or create…

嵌入式Linux開發實操(九):CAN接口開發

前言: CAN網絡在汽車中的使用可以說相當廣泛。而CAN網絡需要的收發器最常用的就是NXP 的TJA1042: CAN網絡:

605. 種花問題

鏈接 假設有一個很長的花壇&#xff0c;一部分地塊種植了花&#xff0c;另一部分卻沒有。可是&#xff0c;花不能種植在相鄰的地塊上&#xff0c;它們會爭奪水源&#xff0c;兩者都會死去。給你一個整數數組 flowerbed 表示花壇&#xff0c;由若干 0 和 1 組成&#xff0c;其中…

8/16總結

WebSocket是雙向通信協議&#xff0c;模擬Socket協議&#xff0c;可以雙向發送或者接收信息 而Http是單向的 WebSocket是需要瀏覽器和服務器握手進行建立連接的 而http是瀏覽器發起向服務器的連接&#xff0c;服務器預先并不知道這個連接 WebSocket在建立握手時&#xff0c;數…

Python3內置函數大全

吐血整理 Python3內置函數大全 1.abs()函數2.all()函數3.any()函數4.ascii()函數5.bin()函數6.bool()函數7.bytes()函數8.challable()函數9.chr()函數10.classmethod()函數11.complex()函數12.complie()函數13.delattr()函數14.dict()函數15.dir()函數16.divmod()函數17.enumer…

注解@JsonInclude

注解JsonInclude 1. 注解由來 JsonInclude是一個用于Java類中字段或方法的注解&#xff0c;它來自于Jackson庫。Jackson庫是一個用于處理JSON數據的流行開源庫&#xff0c;在Java對象和JSON之間進行序列化和反序列化時經常被使用。 2. 注解示例 下面是JsonInclude注解的一個…

【kubernetes】Pod控制器

目錄 Pod控制器及其功用 pod控制器有多種類型 1、ReplicaSet ReplicaSet主要三個組件組成 2、Deployment 3、DaemonSet 4、StatefulSet 5、Job 6、Cronjob Pod與控制器之間的關系 1、Deployment 查看控制器配置 查看歷史版本 2、SatefulSet 為什么要有headless&…

2023-08-18力扣每日一題

鏈接&#xff1a; 1388. 3n 塊披薩 題意&#xff1a; 一個長度3n的環&#xff0c;選n次數字&#xff0c;每次選完以后相鄰的數字會消失&#xff0c;求選取結果最大值 解&#xff1a; 這波是~~&#xff08;ctrl&#xff09;CV工程師了~~ 核心思想是選取n個不相鄰的元素一定…

無涯教程-Perl - splice函數

描述 此函數從LENGTH元素的OFFSET元素中刪除ARRAY元素,如果指定,則用LIST替換刪除的元素。如果省略LENGTH,則從OFFSET開始刪除所有內容。 語法 以下是此函數的簡單語法- splice ARRAY, OFFSET, LENGTH, LISTsplice ARRAY, OFFSET, LENGTHsplice ARRAY, OFFSET返回值 該函數…

Vue 項目運行 npm install 時,卡在 sill idealTree buildDeps 沒有反應

解決方法&#xff1a;切換到淘寶鏡像。 以下是之前安裝的 xmzs 包&#xff0c;用于控制切換淘寶鏡像。 該截圖是之前其他項目切換淘寶鏡像的截圖。 切換鏡像后&#xff0c;順利執行 npm install 。

生成國密密鑰對

在線生成國密密鑰對 生成的密鑰對要妥善保管&#xff0c;丟失是無法找回的。

selinux

一、selinux的說明 二、selinux的工作原理 三、selinux的啟動、關閉與查看 Enforcing和permissive都是臨時的&#xff0c;重啟還是依據配置文件中&#xff0c;禁用selinux&#xff0c;修改配置文件&#xff1a; 之后重啟生效 四、selinux對linux服務的影響

SpringBoot 接口調用出現亂碼解決 中文亂碼

SpringBoot 接口調用出現亂碼解決 package com.cxjg.mvc.util;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springfra…

相同數字的積木游戲

題目描述 題目描述 小華和小薇一起通過玩積木游戲學習數學。 他們有很多積木&#xff0c;每個積木塊上都有一個數字&#xff0c;積木塊上的數字可能相同。 小華隨機拿一些積木挨著排成一排&#xff0c;請小薇找到這排積木中數字相同目所處位置最遠的2塊積木塊&#xff0c;計算…

【JAVA】我們該如何規避代碼中可能出現的錯誤?(一)

個人主頁&#xff1a;【&#x1f60a;個人主頁】 系列專欄&#xff1a;【??初識JAVA】 文章目錄 前言三種類型的異常異常處理JAVA內置異常類Exception 類的層次 前言 異常是程序中的一些錯誤&#xff0c;但并不是所有的錯誤都是異常&#xff0c;并且錯誤有時候是可以避免的&…

【BASH】回顧與知識點梳理(三十三)

【BASH】回顧與知識點梳理 三十三 三十三. 認識系統服務 (daemons)33.1 什么是 daemon 與服務 (service)早期 System V 的 init 管理行為中 daemon 的主要分類 (Optional)systemd 使用的 unit 分類systemd 的配置文件放置目錄systemd 的 unit 類型分類說明 33.2 透過 systemctl…

Grounding dino + segment anything + stable diffusion 實現圖片編輯

目錄 總體介紹總體流程 模塊介紹目標檢測&#xff1a; grounding dino目標分割&#xff1a;Segment Anything Model (SAM)整體思路模型結構&#xff1a;數據引擎 圖片繪制 集成樣例 其他問題附錄 總體介紹 總體流程 本方案用到了三個步驟&#xff0c;按順序依次為&#xff1a…

Tomcat 部署優化

Tomcat Tomcat 開放源代碼web應用服務器&#xff0c;是由java代碼開發的 tomcat就是處理動態請求和基于java代碼的頁面開發 可以在html當中寫入java代碼&#xff0c;tomcat可以解析html頁面當中的iava&#xff0c;執行動態請求 動態頁面機制有問題&#xff1a;不對tomcat進行優…

vue 使用indexDB 簡單完整邏輯

1 npm npm install idb 2 代碼 <template><div><p>Data: {{ data }}</p><button click"fetchData">Fetch Data</button></div> </template><script> import { openDB } from idb;export default {data() {…

eqtl-GWAS和GWAS-GWAS

目前教程中有eqtl-GWAS和GWAS-GWAS兩種模式&#xff0c;其他模式比較少見&#xff0c;還未進行開發 數據類型cc為分類變量即case/control&#xff0c;quant為連續變量&#xff0c;eqtl數據默認quant coloc.abf有兩個比較需要注意的點&#xff0c;就是數據集中N是代表樣本量&am…