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…