- 作者:老汪软件技巧
- 发表时间:2024-09-02 10:03
- 浏览量:
面试官的题库,让一部分人先拿Offer!
suspend,是 Kotlin 当中的一个关键字,它主要的作用是用于 定义“挂起函数”。
suspend背后的转换
同样的一个函数,加上 suspend 修饰以后,它的函数类型就会发生改变
可见,同样是 Int 作为参数,Double 作为返回值,有没有 suspend 修饰,它们两者的函数类是不一样的。
“suspend (Int) -> Double”与“(Int) -> Double”并不能互相赋值
高阶函数中 Kotlin 的函数类型,其实只跟参数、返回值、接收者相关, 不过现在又加了一条:还跟 suspend 相关
那么,**suspend **修饰的函数,到底会变成什么类型?如果你将挂起函数与前面“回调地狱的代 码”放在一起对比,应该可以找到一些头绪
其实,挂起函数的本质,就是 Callback
当 Kotlin 编译器检测到 suspend 关键字修饰的函数以后,就会自 动将挂起函数转换成带有CallBack 的函数
如果我们将上面的挂起函数反编译成java,结果会是这样
从反编译的结果来看,挂起函数确实变成了一个带有 CallBack 的函数,只是这个 CallBack 换了个名字,叫做 Continuation。我们来看看 Continuation 在 Kotlin 中的定义:
根据以上定义我们其实能发现,Continuation 本质上也就是一个带有泛型参数的 CallBack,只是它的名字看起来有点吓人而已。这个“从挂起函数转换成 CallBack 函数”的过程,被叫做是CPS 转换(Continuation-Passing-Style Transformation)。
以下函数签名的变化
函数的类型发生了变化:suspend ()->String变成了(Continuation)-> Any?
就意味着,如果你在 Java 中访问一个 Kotlin 挂起函数 getUserInfo(),会看到 Java 里的getUserInfo() 的类型是“(Continuation)-> Object”(即接收 Continuation 为参数,返回值是Object)。
到这里,我们就只剩下最后一个问题需要搞清楚了,那就是:Continuation 到底是什么
Continuation 是什么
让我结合前面的代码案例,用更加通俗的语言解释给你听。首先,我们只需要把握住 Continuation 的词源 Continue 即可。Continue 是“继续”的意思
Continuation 则是“接下来要做的事情”。放到程序中,Continuation 就代表了,“程序继续运行下去需要执行的代码”,“接下来要执行的代码”,或者是“剩下的代码”。
就以上面的代码为例,当程序运行 getUserInfo() 这个挂起函数的时候,它的“Continuation”则是下图红框的代码:
这样理解了 Continuation 以后,CPS 也就容易理解了,它其实就是将程序接下来要执行的代码进行传递的一种模式。
而 CPS 转换,就是将原本的同步挂起函数转换成 CallBack 异步代码的过程。这个转换是编译器在背后做的,我们程序员对此并无感知
现在我们可以理出一条线索了:协程之所以是非阻塞,是因为它支持“挂起和恢复”;而挂起和恢复的能力,主要是源自于“挂起函数”;而挂起函数是由 CPS 实现的,其中的Continuation,本质上就是 Callback