Kotlin 作用域函数全解析:let、run、with、apply、also 应该怎么选?

Kotlin 提供了一套优雅的"作用域函数"(Scope Functions),包括:let、run、with、apply 和 also。它们看起来相似,行为上也有交集,但却各有侧重。掌握它们的使用场景,不仅能让代码更简洁,还能让意图更加明确。


📌 什么是作用域函数?

作用域函数的作用是:在一个对象的上下文中执行一段代码块,并返回某个结果。

所有作用域函数的行为可以分成两方面:

分类 内容
上下文对象访问方式 通过 this 还是 it 来引用对象
返回值类型 返回原始对象,还是返回 lambda 表达式的最后一行结果

🧩 总览对比表

函数 访问方式 返回值 是否扩展函数 常见用途
let it lambda 结果 ✅ 可空判断、链式转换、局部作用域
run this lambda 结果 ✅ 表达式计算、初始化逻辑
with this lambda 结果 ❌ 对已有对象进行多次操作
apply this 对象本身 ✅ 初始化对象属性链式构建
also it 对象本身 ✅ 调试、日志、链式副作用

🧪 逐个详解 + 示例

1. let:适合可空对象链式处理

let 最大的特点是使用 it 访问对象,并返回 lambda 表达式最后的值,常用于安全调用、转换或临时作用域。

kotlin 复制代码
val name: String? = "Kotlin"

val length = name?.let {
    println("名字是:$it")
    it.length
}

常见用途:

  • 安全调用链(null 安全)
  • 表达式转换(如 map)
  • 限定临时作用域变量名(如 it 改为具体名)

2. run:适合表达式求值或初始化计算

run 使用 this 引用对象,返回表达式的结果。可以用于对象配置,也可以直接作为代码块返回值。

kotlin 复制代码
val result = "Hello".run {
    println("原字符串是 $this")
    length + 10
}

常见用途:

  • 表达式求值
  • 对象初始化后立即使用

3. with:适合已有对象的多次操作

with 不是扩展函数,而是一个普通函数。它的写法比较自然,像在"带着对象做事情"。

kotlin 复制代码
val builder = StringBuilder()
val result = with(builder) {
    append("Hello, ")
    append("World!")
    toString()
}

常见用途:

  • 构造复杂对象时,连续操作对象属性
  • 避免重复写对象名

4. apply:返回对象自身,用于构建对象

apply 使用 this 引用对象,返回对象本身。常用于构造函数 + 初始化链式调用。

kotlin 复制代码
val user = User().apply {
    name = "Alice"
    age = 20
}

常见用途:

  • 初始化对象并配置属性
  • DSL(领域特定语言)构建,如 View.apply {}

5. also:副作用处理,不改变原值

also 使用 it 引用对象,返回对象本身。适合用于打印、日志、调试、不影响主逻辑的操作。

kotlin 复制代码
val numbers = mutableListOf("one", "two", "three")
    .also { println("原始数据:$it") }
    .apply { add("four") }

常见用途:

  • 日志打印
  • 调试时插入查看变量值
  • 链式调用中临时操作对象

🎯 使用建议:如何选择?

你可以用以下口诀快速判断:

  • 🤔 我需要结果? → run / with / let
  • 🛠️ 我要改对象? → apply / with
  • 🧪 我想插入副作用? → also
  • ❓ 可能为 null? → ?.let
  • 📦 要链式构建对象? → apply

🧠 小技巧:记住两个维度

plaintext 复制代码
返回谁?
- 返回对象本身:apply, also
- 返回表达式结果:let, run, with

用谁访问对象?
- this:apply, run, with
- it:let, also

相关推荐
古法老登瞎折腾5 小时前
大数据智能运维实战(十一):运维 MCP 的工程化——权限、限流、审计与错误处理
java·大数据·运维·spring ai·mcp
智能运维指南6 小时前
研制过程“两张皮“怎么破:研制一体化支撑平台的定位、能力边界与落地前提
java·前端·人工智能·嘉为蓝鲸
yz_aiks7 小时前
Spring AI 2.1 ChatMemory 已过时用什么替代:迁移到 Session Memory 实战(JDBC 存储与会话压缩)
java·spring boot·大模型·ai agent·spring ai
金銀銅鐵7 小时前
[Java] 用 GUI 展示 EnumMap 增删键值对时的内部变化
java·后端·ai编程
学长毕设7 小时前
基于SpringBoot的上门洗车服务系统设计与实现
java·spring boot·后端
jason成都7 小时前
RTKLIB-Java 多基线联合RTK:FIX率从0%到91.5%的三层根因修复
java·gnss·rtklib·rtklib_java
鱼宵8 小时前
Stream 终端操作一次讲透:collect、count、reduce 怎么选
java·stream·终端操作
白山编程大哥8 小时前
Java 后端如何优雅地把 List 集合返回给前端
java·前端·list
Linux运维技术栈8 小时前
CVE-2026-91403 高危漏洞修复:Rocky Linux 9 多版本 JDK 环境清理实操
java·linux·运维
On The Road :8 小时前
Java 多线程详解:从入门到线程安全
java·python·安全