Kotlin 的作用域函数(Scope Functions)是一组在对象上下文中执行代码块的高阶函数,通过简洁的语法实现对象操作、空安全处理和链式调用。以下是 ​​5 个核心作用域函数​​的对比及示例:


 一、作用域函数对比表

函数

引用方式

返回值

核心用途

典型场景

apply

this

对象本身

对象配置(设置值)

初始化对象、设置属性

also

it

对象本身

副作用操作(获取值)

日志、验证、链式中间处理

let

it

Lambda 结果

空安全处理、数据转换

可空对象操作、链式转换

run

this

Lambda 结果

对象计算、混合逻辑

访问成员并返回计算结果

with

this

Lambda 结果

非扩展函数版 run

显式传入对象并批量操作


 二、函数详解与代码示例

1. ​apply:对象初始化与配置​

​特点​​:隐式 this(可省略),返回对象自身。

​示例​​:

// 初始化 TextView 并配置属性
val textView = TextView(context).apply {
    text = "Submit"     // 等价于 this.text = "Submit"
    textSize = 16f
    setOnClickListener { showToast() }
}
// 链式配置 AlertDialog
AlertDialog.Builder(this).apply {
    setTitle("警告")
    setMessage("确认删除?")
}.create()

​适用场景​​:密集配置对象属性(如 UI 组件、DTO 对象)。


2. ​also:执行副作用操作​

​特点​​:显式 it,返回对象自身。

​示例​​:

// 链式调用中插入日志
val file = File("data.txt")
    .also { println("创建文件: ${it.path}") } // 打印路径
    .also { it.writeText("Hello") }         // 写入内容

// 验证并传递对象
val user = User(name = "Alice").also {
    require(it.name.isNotEmpty()) // 非空验证
}

​适用场景​​:调试、日志记录、链式调用中的中间操作。


3. ​let:空安全处理与数据转换​

​特点​​:显式 it,返回 Lambda 结果(支持安全调用 ?.let)。

​示例​​:

// 安全处理可空对象
val name: String? = getName()
val greeting = name?.let { 
    "Hello, ${it.uppercase()}"  // it 为非空副本
} ?: "Hello, Guest"

// 链式数据转换
val numbers = listOf(1, 2, 3)
val result = numbers.map { it * 2 }
    .let { it.joinToString("-") } // 转换为 "2-4-6"

​适用场景​​:可空对象操作、类型转换、限定临时变量作用域。


4. ​run:对象计算与混合操作​

​特点​​:隐式 this(可省略),返回 Lambda 结果。

​示例​​:

// 计算文件内容长度
val file = File("data.txt")
val length = file.run {
    if (exists()) readText().length else 0
}

// 混合对象方法与外部函数
val user = User("Bob", 30)
val info = user.run {
    age += 5
    "姓名: $name, 年龄: $age" // 返回字符串
}

​适用场景​​:同时访问对象属性和外部函数、链式操作中的计算。


5. ​with:批量操作已有对象​,直接操作这个传入的对象,取值或者使用方法

​特点​​:非扩展函数,显式传入对象,返回 Lambda 结果。

​示例​​:

val list = mutableListOf("A", "B")
val size = with(list) {
    add("C")            // 直接调用 add()
    remove("A")         // 无需写 list.remove()
    this.size           // 返回结果
}

// 数学计算
val point = Point(3, 4)
val distance = with(point) { 
    sqrt(x * x + y * y) // 直接访问属性
}

​适用场景​​:对已有对象进行多次操作,避免重复写对象名。


 三、选择建议(口诀)

  • ​配置对象​​ → applythis+ 返回自身)

  • ​副作用操作​​ → alsoit+ 返回自身)

  • ​空安全处理​​ → ?.letit+ 返回结果)

  • ​对象计算​​ → run/withthis+ 返回结果)

  • ​链式构建​​ → apply→ also(如 obj.apply{}.also{}

​最佳实践​​:

  • 避免混淆返回值:apply/also返回对象,适合链式配置;let/run/with返回结果(最后一句执行语句),适合生成新值。

        val nullableStr: String? = getName()
        var cc = nullableStr?.let {
            println(it.uppercase())
            "Hello, ${it.uppercase()}"  //返回最后一句执行语句
        } ?: "你好"
    
        println(cc)
     
    
    fun getName(): String? {
        return "zzz";
    }

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐