Kotlin -> 普通Lambda vs 掛起Lambda

1. 普通Lambda vs 掛起Lambda的本質區別

1.1 普通Lambda(同步執行)

val lambda: (Int) -> String = { it.toString() }// 編譯器生成:
class Lambda$1 : Function1<Int, String> {override fun invoke(p1: Int): String {return p1.toString() // 直接返回結果}
}
  • 特點:
    • 同步執行:函數調用后立即返回結果
    • 不能掛起:執行過程中不會暫停
    • 簡單映射:參數和返回類型直接對應
    • 單線程執行:在調用線程上同步完成

1.2 掛起Lambda(異步執行)

val suspendLambda: suspend (Int) -> String = { delay(1000) // 可能掛起it.toString() 
}// 編譯器生成:
class SuspendLambda$1 : SuspendLambda, Function2<Int, Continuation<String>, Any?> {override fun invoke(p1: Int, continuation: Continuation<String>): Any? {// 可能返回實際結果或COROUTINE_SUSPENDED}
}
  • 特點:
    • 異步執行:可能不會立即返回結果
    • 可以掛起:遇到掛起點會暫停執行
    • CPS轉換:需要額外的Continuation參數
    • 狀態機:內部實現為狀態機來處理掛起/恢復

2. CPS (Continuation Passing Style) 轉換原理

2.1 什么是CPS

CPS是一種編程風格,函數不直接返回結果,而是將結果傳遞給一個continuation(繼續執行的回調)

// 直接風格 (Direct Style)
fun add(a: Int, b: Int): Int = a + b// CPS風格
fun addCPS(a: Int, b: Int, cont: (Int) -> Unit) {cont(a + b) // 將結果傳遞給continuation
}

2.2 Kotlin掛起函數的CPS轉換

// 用戶編寫的掛起函數
suspend fun fetchUser(id: Int): User {val response = httpCall(id) // 可能掛起return parseUser(response)
}// 編譯器轉換后的實際簽名
fun fetchUser(id: Int, continuation: Continuation<User>): Any? {// 返回User或COROUTINE_SUSPENDED
}

3. 為什么需要額外的Continuation參數?

3.1 掛起和恢復機制

suspend fun example(): String {println("Before delay")delay(1000) // 掛起點println("After delay") return "Done"
}// 編譯后的狀態機邏輯(簡化)
fun example(continuation: Continuation<String>): Any? {val sm = continuation as? ExampleStateMachine ?: ExampleStateMachine(continuation)when (sm.label) {0 -> {println("Before delay")sm.label = 1val result = delay(1000, sm) // 傳遞狀態機作為continuationif (result == COROUTINE_SUSPENDED) return COROUTINE_SUSPENDED// 如果沒掛起,繼續執行}1 -> {println("After delay")return "Done"}}
}

3.2 Continuation的作用

interface Continuation<in T> {val context: CoroutineContextfun resumeWith(result: Result<T>) // 恢復執行的回調
}
  • Continuation負責:
    • 保存執行狀態:當前執行到哪個步驟
    • 恢復執行:異步操作完成后繼續執行
    • 異常處理:傳遞異步操作中的異常
    • 上下文管理:攜帶協程上下文信息

4. 詳細的轉換規則對比

4.1 普通Lambda轉換規則

// 原始類型:(P1, P2, ..., Pn) -> R
// 轉換為:Function(n)<P1, P2, ..., Pn, R>val lambda1: () -> Int = { 42 }
// 轉換為:Function0<Int>val lambda2: (String) -> Int = { it.length }
// 轉換為:Function1<String, Int>val lambda3: (Int, String) -> Boolean = { i, s -> i > 0 && s.isNotEmpty() }
// 轉換為:Function2<Int, String, Boolean>

4.2 掛起Lambda轉換規則

// 原始類型:suspend (P1, P2, ..., Pn) -> R
// 轉換為:Function(n+1)<P1, P2, ..., Pn, Continuation<R>, Any?>val suspendLambda1: suspend () -> Int = { delay(1000)42 
}
// 轉換為:Function1<Continuation<Int>, Any?>val suspendLambda2: suspend (String) -> Int = { delay(1000)it.length 
}
// 轉換為:Function2<String, Continuation<Int>, Any?>val suspendLambda3: suspend (Int, String) -> Boolean = { i, s ->delay(1000)i > 0 && s.isNotEmpty()
}
// 轉換為:Function3<Int, String, Continuation<Boolean>, Any?>

4.3 帶接收者的Lambda轉換

// 普通帶接收者Lambda
val receiverLambda: String.() -> Int = { this.length }
// 轉換為:Function1<String, Int>// 掛起帶接收者Lambda
val suspendReceiverLambda: suspend String.() -> Int = { delay(1000)this.length 
}
// 轉換為:Function2<String, Continuation<Int>, Any?>

5. 為什么返回類型是Any?而不是具體類型?

5.1 掛起函數的兩種返回情況

suspend fun maybeSupsend(): String {return if (someCondition) {"immediate result" // 立即返回} else {delay(1000) // 掛起,稍后恢復"delayed result"}
}// 編譯后
fun maybeSupsend(cont: Continuation<String>): Any? {return if (someCondition) {"immediate result" // 返回String} else {// 啟動異步操作,返回掛起標記return COROUTINE_SUSPENDED // 返回特殊標記}
}

5.2 COROUTINE_SUSPENDED標記

// kotlin.coroutines.intrinsics
public val COROUTINE_SUSPENDED: Any = CoroutineSingletons.COROUTINE_SUSPENDED// 使用示例
fun someFunction(): Any? {return when {canReturnImmediately -> "actual result"needsToSuspend -> COROUTINE_SUSPENDEDelse -> null}
}

6. 完整的對比示例

6.1 普通Lambda的完整流程

val lambda: (Int) -> String = { it.toString() }// 編譯生成
class Lambda$1 : Function1<Int, String> {override fun invoke(p1: Int): String {return p1.toString()}
}// 調用流程
val result = lambda(42) // 直接調用invoke,立即得到結果 "42"

6.2 掛起Lambda的完整流程

val suspendLambda: suspend (Int) -> String = { delay(1000)it.toString() 
}// 編譯生成
class SuspendLambda$1 : SuspendLambda, Function2<Int, Continuation<String>, Any?> {var label = 0var p$0: Int = 0 // 保存參數override fun invoke(p1: Int, continuation: Continuation<String>): Any? {val sm = create(p1, continuation) as SuspendLambda$1return sm.invokeSuspend(Unit)}override fun invokeSuspend(result: Result<Any?>): Any? {when (label) {0 -> {label = 1val delayResult = delay(1000, this)if (delayResult == COROUTINE_SUSPENDED) return COROUTINE_SUSPENDED}1 -> {return p$0.toString()}}}
}// 調用流程
// 1. 調用invoke(42, continuation)
// 2. 可能返回COROUTINE_SUSPENDED(掛起)
// 3. 異步操作完成后,通過continuation.resumeWith恢復
// 4. 最終得到結果 "42"

7. 總結:根本區別

特性普通Lambda掛起Lambda
執行模式同步,立即返回異步,可能掛起
參數轉換直接映射額外添加Continuation
返回類型保持原類型改為Any?(支持掛起標記)
內部實現簡單函數調用狀態機 + CPS
繼承關系Function接口SuspendLambda + Function接口
調用約定直接調用CPS調用約定

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

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

相關文章

Apache Ignite 中如何配置和啟用各類監控指標

這段文檔是關于 Apache Ignite 中如何配置和啟用各類監控指標&#xff08;Metrics&#xff09; 的詳細說明。核心思想是&#xff1a;“指標收集有性能開銷&#xff0c;因此默認不開啟所有指標&#xff0c;需要你按需手動開啟。” 下面我們來逐層拆解、通俗易懂地理解這些內容。…

uniapp x swiper/image組件mode=“aspectFit“ 圖片有的閃現后黑屏

部分安卓機針對大寫.JPG 有的豎圖正常&#xff0c;橫圖/正方形不對。解決方案&#xff1a;加border-radius: 1rpx;就行<!-- 圖片預覽彈出框 --><fui-backdrop v-model:visible"imgPreviewVisible" :closable"true" onclick"imgPreviewVisibl…

conda安裝jupter

conda自帶的jupter本來在base里沒有在pytorch環境中 安裝jupter conda install nb_conda 此擴展程序在 Jupyter 文件瀏覽器中添加了一個 Conda 選項卡。選擇 Conda 選項卡將顯示&#xff1a; 當前存在的 Conda 環境列表當前配置的通道中可用的 Conda 包列表&#xff08;htt…

嵌入式操作系統快速入門(1):快速入門操作系統常見基礎概念

快速體會操作系統常見基礎概念 1 初識基本概念 1.1 操作系統 一個軟件程序&#xff1b;用于解決計算機多任務執行時的資源爭搶問題&#xff1b;管理計算機中的各種資源&#xff0c;確保計算機正常完成各種工作&#xff08;任務&#xff09;&#xff0c;解決多任務環境中任務的調…

網絡安全-同形異義字攻擊:眼見并非為實(附案例詳解)

什么是同形異義字攻擊&#xff1f;對人眼而言&#xff0c;一切看起來完全正常。但實際上&#xff0c;例如單詞 Ηоmоgraph 并不完全等同于單詞 Homograph。它們之間的差異非常細微&#xff0c;難以察覺。Ηоmоgraph 實際上包含了幾個非拉丁字母。在本例中&#xff0c;我們將…

windows服務器 maven 配置環境變量,驗證maven環境變量是否配置成功

前置條件&#xff1a;先確認對應版本的jdk已安裝配置好&#xff0c;可使用java -version檢測; 我使用的apache-maven-3.6.3是對應jdk1.8 1.找到系統變量配置窗口 以windows server2019為例&#xff0c;右鍵計算機屬性&#xff0c; 高級系統設置–》環境變量–》系統變量2.新建M…

安裝 docker compose v2版 筆記250731

安裝 docker compose v2版 筆記250731 簡述 v2版是插件形式 確認系統要求, 已安裝 Docker Engine&#xff08;版本 20.10.5 或更高&#xff09; 安裝方式可分為 apt 或 yum 安裝 (能自動升級) apt install docker-compose-pluginyum install docker-compose-plugin 手動二…

PHP 5.5 Action Management with Parameters (English Version)

PHP 5.5 Action Management with Parameters (English Version) Here’s a PHP 5.5 compatible script that uses URL parameters instead of paths for all operations: <?php // Start session for persistent storage session_start();// Initialize the stored actio…

GR-3(4B) 技術報告--2025.7.23--字節跳動 Seed

0. 前言 前兩天字節發布了GR-3&#xff0c;粗略的看了一下&#xff0c;在某些方面超過了SOTA pi0&#xff0c;雖然不開源&#xff0c;但是也可以來看一看。 官方項目頁 1. GR-3模型 1.1 背景 在機器人研究領域&#xff0c;一直以來的目標就是打造能夠幫助人類完成日常任務…

Linux網絡編程:UDP 的echo server

目錄 前言&#xff1a; 一、服務端的實現 1、創建socket套接字 2、綁定地址信息 3、執行啟動程序 二、用戶端的實現 總結&#xff1a; 前言&#xff1a; 大家好啊&#xff0c;前面我們介紹了一些在網絡編程中的一些基本的概念知識。 今天我們就借著上節課提到的&#…

AI+金融,如何跨越大模型和場景鴻溝?

文&#xff5c;白 鴿編&#xff5c;王一粟當AI大模型已開始走向千行百業之時&#xff0c;備受看好的金融行業&#xff0c;卻似乎陷入了落地瓶頸。打開手機銀行想查下貸款額度&#xff0c;對著屏幕說了半天&#xff0c;AI客服卻只回復 “請點擊首頁貸款按鈕”&#xff1b;客戶經…

深度解析:從零構建跨平臺對象樹管理系統(YongYong框架——QT對象樹機制的現代化替代方案)

一、技術背景與核心價值 1.1 QT對象樹的局限性 在Qt框架中&#xff0c;QObject通過對象樹機制實現了革命性的對象管理&#xff1a; #mermaid-svg-SvqKmpFjg76R02oL {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Sv…

力扣46:全排列

力扣46:全排列題目思路代碼題目 給定一個不含重復數字的數組 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意順序 返回答案。 思路 看到所有可能首先想到的就是回溯。 回溯的結束條件也很好寫&#xff0c;用數組的長度來判斷即可。這道題的難點主要是如何進行判…

mac環境配置rust

rustup 是一個命令行工具&#xff0c;用于管理 Rust 編譯器和相關工具鏈 sh 體驗AI代碼助手 代碼解讀復制代碼curl --proto ‘https’ --tlsv1.2 -sSf https://sh.rustup.rs | sh使得 Rust 的安裝在當前 shell 環境中生效 如果你使用的是 bash, zsh 或其他類似的 shell&#xf…

腳手架搭建React項目

腳手架搭建項目 1. 認識腳手架工具 1.1. 前端工程的復雜化 1.1.1. 如果只是開發幾個小的demo程序&#xff0c;那么永遠不要考慮一些復雜的問題&#xff1a; 比如目錄結構如何組織劃分&#xff1b;比如如何關鍵文件之間的相互依賴&#xff1b;比如管理第三方模塊的依賴&#xff…

Golang 調試技巧:在 Goland 中查看 Beego 控制器接收的前端字段參數

&#x1f41b; Golang 調試技巧&#xff1a;在 Goland 中查看 Beego 控制器接收的前端字段參數 在使用 Beego 開發 Web 項目時&#xff0c;我們常常會在控制器中通過 c.GetString()、c.GetInt() 等方法獲取前端頁面傳過來的字段值。而在調試過程中&#xff0c;如何在 Goland 中…

sqli-labs:Less-2關卡詳細解析

1. 思路&#x1f680; 本關的SQL語句為&#xff1a; $sql"SELECT * FROM users WHERE id$id LIMIT 0,1";注入類型&#xff1a;數值型提示&#xff1a;參數id無需考慮閉合問題&#xff0c;相對簡單 2. 手工注入步驟&#x1f3af; 我的地址欄是&#xff1a;http://l…

TRAE 軟件使用攻略

摘要TRAE 是一款集成了人工智能技術的開發工具&#xff0c;旨在為開發者提供高效、智能的編程體驗。它包括三個主要組件&#xff1a;TRAE IDE、TRAE SOLO 和 TRAE 插件。無論是編程新手還是經驗豐富的開發者&#xff0c;都可以通過 TRAE 提高工作效率和代碼質量。標題一&#x…

將開發的軟件安裝到手機:環境配置、android studio設置、命令行操作

將開發的軟件安裝到手機環境配置android studio4.1.2安裝命令行操作環境配置 注意&#xff1a;所有的工具的版本都需要根據當下自己的軟件需要的。 Node&#xff1a;14.16.0 &#xff08;如果安裝了npm&#xff0c;可以使用npm進行當前使用node版本的更改&#xff09; &#x…

Jmeter 命令行壓測、HTML 報告、Jenkins 配置目錄

Jmeter 命令行壓測 & 生成 HTML 測試報告 通常 Jmeter 的 GUI 模式僅用于調試&#xff0c;在實際的壓測項目中&#xff0c;為了讓壓測機有更好的性能&#xff0c;多用 Jmeter 命令行來進行壓測。 官方&#xff1a;Jmeter 最佳實踐 同時&#xff0c;JMeter 也支持生成 HT…