Kotlin内置函数之also

Kotlin 的 ‌**also‌ 函数是一个‌ 作用域函数‌,主要用于在链式调用中执行‌ 副作用操作**‌(如日志记录、数据校验等),同时保留原对象并返回它。与 apply 类似,但它通过 it 引用对象,而非隐式 this。以下是其核心特性和典型用法:


基本特性

  1. 函数签名‌:

    kotlin 复制代码
    public inline fun <T> T.also(block: (T) -> Unit): T
    • T 的扩展函数,接收一个以 T 为参数的 lambda((T) -> Unit)。
    • 返回原对象本身 ‌(即 this),允许链式调用。
  2. 核心用途‌:

    • 在对象操作流程中插入‌副作用代码‌(如日志、校验)。
    • 链式调用中保留原对象,同时执行额外操作。

使用示例

示例 1:记录对象状态

scss 复制代码
val list = listOf(1, 2, 3)
    .also { println("初始列表: $it") } // 打印日志,返回原列表
    .map { it * 2 }
    .also { println("处理后列表: $it") }

示例 2:数据校验

kotlin 复制代码
fun createUser(name: String, age: Int) = User(name, age)
    .also { 
        require(it.age >= 0) { "年龄不能为负数" } // 校验年龄
    }

示例 3:链式调用中修改对象

scss 复制代码
val file = File("data.txt")
    .also { it.createNewFile() } // 创建文件,返回 File 对象
    .also { it.setWritable(true) }

apply 的区别

函数 参数形式 对象引用 典型场景
‌**also**‌ (T) -> Unit it 副作用操作(如日志、校验)
‌**apply**‌ T.() -> Unit this 对象属性初始化配置
  • ‌**also‌ 更强调‌ 显式引用对象**‌(通过 it),适合需要操作对象但无需直接访问其属性的场景。
  • ‌**apply‌ 更适用于‌ 隐式配置对象属性**‌(直接通过 this 访问)。

关键细节

  1. 显式对象引用 ‌:在 also 的 lambda 中,通过 it 操作对象(可自定义参数名):

    scss 复制代码
    user.also { u ->
        println(u.name) // 重命名为 u,避免嵌套作用域中的 it 歧义
    }
  2. 空安全操作 ‌:结合 ?. 安全调用,避免空指针:

    kotlin 复制代码
    val nameLength = user?.name
        ?.also { println("非空名称: $it") } // 仅在 name 非空时执行
        ?.length
  3. 与构造函数配合‌:

    ini 复制代码
    val person = Person("Alice").also {
        it.age = 30 // 补充初始化构造函数未涵盖的属性
    }

适用场景

  1. 调试日志‌:

    scss 复制代码
    dataProcessor.process(data)
        .also { log("处理结果: $it") }
        .upload()
  2. 链式调用中插入操作‌:

    scss 复制代码
    val result = listOf(1, 2, 3)
        .filter { it > 1 }
        .also { println("过滤后集合: $it") } // 中间步骤日志
        .sum()
  3. 对象深拷贝或备份‌:

    scss 复制代码
    val original = mutableListOf(1, 2, 3)
    val copy = original.toList().also { 
        original.clear() // 不影响 copy
    }
  4. 资源释放前操作‌:

    scss 复制代码
    connection.open()
        .also { it.setTimeout(5000) }
        .use { /* 自动关闭连接 */ }

注意事项

  1. 避免滥用 ‌:若仅需配置对象属性,优先用 apply(代码更简洁)。
  2. 副作用管理 ‌:确保 also 中的操作不会破坏对象状态或逻辑。
  3. 性能优化‌:作为内联函数,无额外运行时开销。

总结

  • 使用 also 的场景:

    • 需在链式调用中‌插入日志、校验等副作用代码‌。
    • 需显式引用对象(it)执行操作,同时保留原对象。
  • apply 的对比:

    • also:显式操作对象,强调副作用。
    • apply:隐式配置对象属性,强调初始化。
相关推荐
CYRUS_STUDIO2 小时前
一文搞懂 Frida Stalker:对抗 OLLVM 的算法还原利器
android·逆向·llvm
zcychong3 小时前
ArrayMap、SparseArray和HashMap有什么区别?该如何选择?
android·面试
CYRUS_STUDIO3 小时前
Frida Stalker Trace 实战:指令级跟踪与寄存器变化监控全解析
android·逆向
ace望世界8 小时前
android的Parcelable
android
顾林海8 小时前
Android编译插桩之AspectJ:让代码像特工一样悄悄干活
android·面试·性能优化
叽哥8 小时前
Flutter Riverpod上手指南
android·flutter·ios
循环不息优化不止8 小时前
安卓开发设计模式全解析
android
诺诺Okami8 小时前
Android Framework-WMS-层级结构树
android
alexhilton19 小时前
面向开发者的系统设计:像建筑师一样思考
android·kotlin·android jetpack
CYRUS_STUDIO1 天前
用 Frida 控制 Android 线程:kill 命令、挂起与恢复全解析
android·linux·逆向