当前位置:网站首页>有趣的 Kotlin 0x0E:DeepRecursiveFunction
有趣的 Kotlin 0x0E:DeepRecursiveFunction
2022-08-04 04:37:00 【AndroidKt】
前言
DeepRecursiveFunction
是 Kotlin
在 1.4.0 版本上尝试解决深度递归导致 StackOverflowError
问题的试行方案。在最新发布的 1.7.0 版本上正式 Stable
。面对由于递归导致的栈溢出问题,一般我们采用两种解决办法:
- 增加栈大小
- 改写代码,采用非递归方式实现
Kotlin 通过定义 DeepRecursiveFunction
深度递归类型来实现非递归方式的改写。
官方建议:递归深度操作 1000 考虑使用 DeepRecursiveFunction
。(Consider using deep recursive functions in your code where your recursion depth exceeds 1000 calls.)
语法
定义
public class DeepRecursiveFunction<T, R>(
internal val block: suspend DeepRecursiveScope<T, R>.(T) -> R
)
T
为传入参数类型;R
为输出结果类型;block
函数体。
调用
public abstract suspend fun callRecursive(value: T): R
用于“递归”调用DeepRecursiveFunction
public operator fun DeepRecursiveFunction<*, *>.invoke(value: Any?): Nothing
操作符重载,以便 DeepRecursiveFunction
可以通过()
操作符调用,当然也可以选择直接调用invoke
函数。
看官方给出的示例对比,可能更直观一点。
示例
实现二叉树的深度计算:原始递归DeepRecursiveFunction。
原始递归
fun depth(t: Tree?): Int =
if (t == null) 0 else maxOf(
depth(t.left), // recursive call one
depth(t.right) // recursive call two
) + 1
DeepRecursiveFunction
val calculateDepth = DeepRecursiveFunction<Tree?, Int> {
t ->
if (t == null) 0 else maxOf(
callRecursive(t.left),
callRecursive(t.right)
) + 1
}
对比上面两种代码可以看出,开发者可以很容易从原始递归方式改写成 DeepRecursiveFunction
方式。这就是 Kotlin 希望达到的低开发成本效果。当开发者因采用原始递归方式时递归层级过深出现 StackOverflowError
问题时, 简易调整为 DeepRecursiveFunction
,可以在避免大量改写代码的前提下帮助开发者快速解决栈溢出问题。
Run
fun main() {
// Generate a tree with a depth of 100_000
val deepTree = generateSequence(Tree(null, null)) {
prev ->
Tree(prev, null)
}.take(4).last()
println(calculateDepth(deepTree)) // 100000
println(depth(deepTree)) // 100000
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LPAOp9KH-1659446563474)(http://qiniu.fultter.club/image-20220731130252997.png)]
源码
关于 DeepRecursiveFunction
的源码全部集中于 DeepRecursive.kt
文件中,主要包含三个类:
- DeepRecursiveFunction
- DeepRecursiveScope
- DeepRecursiveScopeImpl
具体的实现集中在 DeepRecursiveScopeImpl
类中,通过协程机制实现递归逻辑。
suspend
模拟向下压栈 ️,resume
模拟向上出栈 ️,实现类似递归调用的效果🪆。
结语
每一颗语法糖背后,总有几个 Kotlin 的工程师在为我们负重前行。🥸
边栏推荐
- QT 如何识别文件的编码格式
- Postgresql source code (66) insert on conflict grammar introduction and kernel execution process analysis
- 深度学习——以CNN服装图像分类为例,探讨怎样评价神经网络模型
- 嵌入式数据库开发编程MySQL(全)
- 如何简化现代电子采购的自动化?
- 八年软件测试工程师带你了解-测试岗进阶之路
- 【21天学习挑战赛】图像的旋转问题(二维数组)
- 【机器学习】21天挑战赛学习笔记(一)
- 拿捏JVM性能优化(自己笔记版本)
- 2022 Hangzhou Electric Power Multi-School League Game 5 Solution
猜你喜欢
Explain详解与实践
结构体函数练习
软件测试如何系统规划学习呢?
深度学习21天——卷积神经网络(CNN):实现mnist手写数字识别(第1天)
本周四晚19:00知识赋能第4期直播丨OpenHarmony智能家居项目之设备控制实现
基于 SSE 实现服务端消息主动推送解决方案
How to keep the source code confidential in the development under the burning scenario
drools从下载到postman请求成功
2022杭电多校联赛第五场 题解
There is an 8 hour difference between the docker installation of mysql and the host.
随机推荐
【Ryerson情感说话/歌唱视听数据集(RAVDESS) 】
数据治理平台项目总结和分析
马尔可夫链
Stop behind.
Hangdian Multi-School-Slipper- (tree map conversion + virtual point mapping)
The Shell function
Simple operation of the file system
How to keep the source code confidential in the development under the burning scenario
怎么把elastic中的异常登录ip和日志自动导出或抓取到数据库中?
备份工具pg_dump的使用《postgres》
Introduction and application of go module
Converts XML tags to TXT format (voc conversion for yolo convenient training)
See how DevExpress enriches chart styles and how it empowers fund companies to innovate their business
manipulation of file contents
Mockito unit testing
如何动态添加script依赖的脚本
How to dynamically add script dependent scripts
Hey, I had another fight with HR in the small group!
8.Haproxy 搭建Web集群
FFmpeg —— 录制麦克风声音(附源码)