Kotlin 内联函数详解及实例
Kotlin 内联函数详解及实例
概述
在说内联函数之前,先说说函数的调用过程。
调用某个函数实际上将程序执行顺序转移到该函数所存放在内存中某个地址,将函数的程序内容执行完后,再返回到转去执行该函数前的地方。这种转移操作要求在转去前要保护现场并记忆执行的地址,转回后先要恢复现场,并按原来保存地址继续执行。也就是通常说的压栈和出栈。因此,函数调用要有一定的时间和空间方面的开销。那么对于那些函数体代码不是很大,又频繁调用的函数来说,这个时间和空间的消耗会很大。
那怎么解决这个性能消耗问题呢,这个时候需要引入内联函数了。内联函数就是在程序编译时,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体来直接进行替换。显然,这样就不会产生转去转回的问题,但是由于在编译时将函数体中的代码被替代到程序中,因此会增加目标程序代码量,进而增加空间开销,而在时间代销上不象函数调用时那么大,可见它是以目标代码的增加为代价来换取时间的节省。
inline
在Kotlin中,使用inline修饰符标记内联函数,既会影响到函数本身, 也影响到传递给它的Lambda表达式,这两者都会被内联到调用处。
例如:
inline fun lock<T>(lock: Lock, body: () -> T): T { // ... }
编译器可以直接产生下面的代码, 而不必为参数创建函数对象, 然后再调用这个参数指向的函数:
l.lock() try { foo() } finally { l.unlock() }
noinline
如果一个内联函数的参数中有多个 Lambda 表达式, 而你只希望内联其中的一部分, 你可以对函数的一部分参数添加 noinline 标记:
inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) { // ... }
可内联的 Lambda 表达式只能在内联函数内部调用, 或者再作为可内联的参数传递给其他函数, 但noinline 的 Lambda 表达式可以按照我们喜欢的方式任意使用: 可以保存在域内, 也可以当作参数传递, 等等。
非局部返回(Non-local return)
在Kotlin中, 使用无限定符的通常的return语句, 只能用来退出一个有名称的函数, 或匿名函数. 这就意味着, 要退出一个Lambda表达式, 我们必须使用一个 标签, 无标签的 return 在 Lambda 表达式内是禁止使用的, 因为 Lambda 表达式不允许强制包含它的函数返回:
fun foo() { ordinaryFunction { return // 错误: 这里不允许让 `foo` 函数返回 } }
如果 Lambda 表达式被传递去的函数是内联函数, 那么 return 语句也可以内联, 因此 return 是允许的。
fun foo() { inlineFunction { return // OK: 这里的 Lambda 表达式是内联的 } }
注:
有些内联函数可能并不在自己的函数体内直接调用传递给它的 Lambda 表达式参数, 而是通过另一个执行环境来调用, 比如通过一个局部对象, 或者一个嵌套函数. 这种情况下, 在 Lambda 表达式内, 非局部的控制流同样是禁止的. 为了标识这一点, Lambda 表达式参数需要添加 crossinline修饰符。
inline fun f(crossinline body: () -> Unit) { val f = object: Runnable { override fun run() = body() } // ... }
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
- springboot入门教程(2)_Thymeleaf集成
- VList data structures in C#
- 编程思想 之「语言导论」
- 编程思想 之「对象漫谈」
- Github 项目推荐 | TensorFlow 概率推理工具集 —— probability
- Github 项目推荐 | 用于 C/C++、Java、Matlab/Octave 的特征选择工具箱
- Mercari Price 比赛分享 —— 语言不仅是算法和公式而已
- Github 项目推荐 | GAN 的 Keras 实现案例集合 —— Keras-GAN
- Github 项目推荐 | 微软开源 MMdnn,模型可在多框架间转换
- 半自动化运维之动态添加数据文件(一) (r5笔记第55天)
- 半自动化运维之动态添加数据文件(二) (r5笔记第56天)
- 11g Active DataGuard初探(r5笔记第54天)
- Github 项目推荐 | 用于构建端对端对话系统和训练聊天机器人的开源库 —— DeepPavlov
- 我身边的一些数据库事故 (r5笔记第52天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 基于python实现名片管理系统
- 记一个OLED编程中文显示函数的坑(留意变量数据类型的范围)
- tp5框架基于Ajax实现列表无刷新排序功能示例
- 浅谈pycharm下找不到sqlalchemy的问题
- PHP实现常用排序算法的方法
- 利用Python实现原创工具的Logo与Help
- PHP+ajax实现上传、删除、修改单张图片及后台处理逻辑操作详解
- 浅谈python下tiff图像的读取和保存方法
- Jmeter(二十五) - 从入门到精通 - JMeter函数 - 下篇(详解教程)
- 解决vscode python print 输出窗口中文乱码的问题
- 对python3新增的byte类型详解
- Python实现的特征提取操作示例
- Linux进程间通信方式之socket使用实例
- python实现图片识别汽车功能
- Mac下Anaconda的安装和使用教程