当前位置: 首页 > news >正文

Kotlin 内联函数(inline)一篇看懂

Kotlin 内联函数(inline)一篇看懂

Kotlin 的 inline 本质上只有一句话:

把函数代码"复制"到调用处,而不是正常函数调用。

它主要解决两个问题:

  1. Lambda 带来的对象创建性能损耗
  2. Lambda 里无法直接 return 的限制

一、先理解:普通函数是怎么执行的

funtest(){println("hello")}funmain(){test()}

正常情况下:

main() ↓ 调用 test() ↓ 执行 println

这是一次"函数跳转"。


二、inline 做了什么

inlinefuntest(){println("hello")}funmain(){test()}

编译后,效果类似:

funmain(){println("hello")}

也就是:

  • 不调用了,直接把代码贴进来
  • 所以叫:内联(inline)
  • 类似 C 语言宏展开

三、为什么 Kotlin 特别需要 inline

因为 Kotlin 大量使用Lambda,例如:

list.forEach{println(it)}

实际上,{ println(it) }这个 Lambda:

  • 会生成对象
  • 会额外产生调用

在 Android 中:

  • RecyclerView
  • Flow
  • Compose
  • 点击事件
  • 高阶函数

都会频繁创建 Lambda。如果大量使用,会产生:

  • 更多 GC
  • 更多对象
  • 性能损耗

所以 Kotlin 官方大量使用 inline。


四、最经典案例:高阶函数

不使用 inline

funexecute(block:()->Unit){block()}

调用:

execute{println("hello")}

这里会生成一个 Lambda 对象,相当于new Function0()。Android 高频调用下会有损耗。

使用 inline 后

inlinefunexecute(block:()->Unit){block()}

调用:

execute{println("hello")}

编译后类似:

println("hello")

Lambda 对象没了。

这就是inline 最大价值


五、Android 为什么大量使用 inline

你会发现很多系统 API 全是inline

  • run
  • let
  • apply
  • also
  • use
  • with
  • forEach

因为这些函数:

  • 调用频率极高
  • 大量使用 Lambda

六、最容易看懂的 Android 实战

场景1:点击防抖

不用 inline

funsetSafeClick(block:()->Unit){block()}// 调用setSafeClick{login()}

会创建 Lambda 对象。

用 inline

inlinefunsetSafeClick(block:()->Unit){block()}

高频点击时:少对象创建,更流畅。


场景2:RecyclerView

RecyclerView bind 非常高频。

不推荐

funbind(block:()->Unit){block()}// onBindViewHolderbind{holder.tv.text=item.name}

每次 bind 创建 Lambda,创建匿名类。列表滑动会产生大量对象。

推荐

inlinefunbind(block:()->Unit){block()}

尤其:瀑布流、长列表、高频刷新,收益明显。


场景3:ViewBinding 扩展

Android 常见:

inlinefun<T:ViewBinding>Activity.binding(block:()->T):T{returnblock()}// 调用valbinding=binding{ActivityMainBinding.inflate(layoutInflater)}

避免 Lambda 额外开销。


场景4:SharedPreferences 编辑

经典:

inlinefunSharedPreferences.edit(action:SharedPreferences.Editor.()->Unit){valeditor=edit()action(editor)editor.apply()}// 调用sp.edit{putString("name","Tom")}

这是 Android 最经典 inline 实战之一。


七、inline 最重要的能力:支持 return

这是很多人真正没理解的点。

普通 Lambda 不能直接 return

funtest(block:()->Unit){block()}funmain(){test{return// 报错}}

因为:return不知道该退出谁。

inline 可以

inlinefuntest(block:()->Unit){block()}funmain(){test{return}println("不会执行")}

因为 inline 后,相当于:

funmain(){returnprintln("不会执行")}

所以合法。这个叫:非局部返回(Non-local return)


八、这就是为什么 forEach 能 return

list.forEach{if(it==3){return}}

因为:forEachinline


九、crossinline 是什么

有时候:inline 虽然允许 return,但函数作者不想让你 return。

inlinefuntest(crossinlineblock:()->Unit){Runnable{block()}.run()}

这里:block被放到了另一个对象里,已经不是原位置执行。

所以:不能 return,否则:

test{return}

逻辑会乱。

所以crossinline= 禁止非局部 return


十、noinline 是什么

inline 默认会:内联所有 Lambda 参数

但有时候,你需要:

  • 保存 Lambda
  • 当对象传递
  • 延迟执行

这时候不能 inline。

inlinefuntest(noinlineblock:()->Unit){}

意思:别内联这个 Lambda


十一、最容易记忆的口诀

关键字作用
inline复制代码进调用处。减少 Lambda 对象,提升性能,支持 return
crossinline允许内联,但禁止 return
noinline不要内联这个 Lambda

十二、Compose 为什么大量 inline

Jetpack Compose 极度依赖:

  • Lambda
  • 高阶函数

例如:

Column{// 本质全是 Lambda}

所以 Compose 内部大量使用inline

否则:UI 每次重组都会大量创建对象。


十三、什么时候适合 inline

推荐:

  • 高频调用:RecyclerView、Compose、Flow、点击事件、ViewBinding
  • 工具函数
  • 高阶函数(函数参数里有Lambdablock: () -> Unit

优先考虑 inline。


十四、什么时候别乱用 inline

inline 会:增加字节码体积

因为:代码被复制了。

所以不适合:

  1. 超大函数

    inlinefunveryBigFunction(){// ...}

    会导致 APK 变大。

  2. 普通函数(没有 Lambda)

    inlinefunadd(a:Int,b:Int)=a+b

    意义很小。


十五、Android 面试高频回答模板

如果面试问:Kotlin inline 有什么作用?

可以这样回答:

inline 本质是编译时函数展开。主要用于高阶函数优化。

Kotlin Lambda 会生成匿名对象,在 Android 高频场景下会带来:对象创建、GC 压力。使用 inline 后:Lambda 不再生成对象,减少函数调用开销,提升性能。

另外 inline 支持非局部 return。

Kotlin 标准库大量使用 inline,例如:letapplyforEachrun

Android 中:RecyclerView、Compose、Flow、点击事件封装,都会大量使用 inline。


十六、最终一张图彻底理解

普通函数:

调用函数 ↓ 创建 Lambda 对象 ↓ 执行

inline:

直接复制代码 ↓ 无对象 ↓ 无调用

十七、推荐你真正去看的源码

非常建议你看这些源码:

  • let
  • apply
  • run
  • forEach
  • use

你会发现几乎全是inline

例如:

publicinlinefun<T>T.apply(block:T.()->Unit):T{block()returnthis}

这会让你真正理解 Kotlin 设计哲学。

http://www.jsqmd.com/news/812853/

相关文章:

  • AI智能体视频创作技能开发:从自动化流程到工程化部署
  • WSL2开发环境自动化配置:aether-kit工具实战指南
  • dotfiles工程化:用Git与符号链接打造可移植的开发环境
  • 基于MCP协议构建AI智能体情报分析服务器:从原理到工程实践
  • 读写分离与查询路由实战:从原理到Spring Boot代码实现
  • 2026年近期华北区域混凝土预制化粪池采购:聚焦产能、定制与交付的硬核供应商选择 - 2026年企业推荐榜
  • 为ClaudeCode编程助手配置Taotoken密钥实现稳定无感调用
  • 怎么查询MongoDB中只包含特定键的文档_对象精确匹配的陷阱
  • 基于MCP与DuckDB的机器人MCAP数据自然语言查询实践
  • Python开发者的瑞士军刀:Tenere插件化CLI工具深度解析
  • 2026年4月国内靠谱的铸铝门生产厂家推荐,别墅铝艺护栏/庭院铸铝大门/别墅铜门/铜门,铸铝门实力厂家哪家靠谱 - 品牌推荐师
  • SpringBoot+Vue 智慧图书管理系统平台完整项目源码+SQL脚本+接口文档【Java Web毕设】
  • 全栈开发真的是万能解药吗?3年全栈开发者的血泪教训
  • Decepticon:基于AI的自主红队平台架构与实战解析
  • 百度文库免费下载终极指南:3分钟快速获取完整文档的完整教程
  • 5个理由告诉你为什么BiliBili-UWP是Windows上最佳的B站客户端
  • 2026年5月超市购物袋采购指南:云南绿象工厂实地探访与实力解析 - 2026年企业推荐榜
  • 2026最权威的降重复率神器解析与推荐
  • 终极PowerBI美化方案:35款专业模板让您的报表设计效率翻倍
  • XOutput 终极指南:让老旧游戏手柄重获新生的完整教程
  • Kubernetes核心库tausik-core:云原生动态配置与资源监听实践
  • AI 原生全域矩阵系统:大模型统一调度与推理优化技术实践
  • Jetro:基于微前端与RPC的现代浏览器扩展开发框架
  • League Akari:英雄联盟终极自动化工具完全指南
  • ARM内存访问指令LDRB与LDREX详解及应用
  • 2026年4月干式打磨台公司推荐,静电除尘器/喷淋塔除尘器/催化燃烧RTO/RCO装置,干式打磨台厂家推荐 - 品牌推荐师
  • 大模型是思考还是猜词?揭秘AI的“类思考”能力!
  • FuseSoC:EDA领域的构建系统与包管理器实战指南
  • 基于MCP协议构建安全可控的AI智能体数据接入层
  • GlibClaw:在Root安卓设备上部署本地AI助手的完整方案