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:隐式配置对象属性,强调初始化。
相关推荐
鸿蒙布道师2 小时前
鸿蒙NEXT开发动画案例5
android·ios·华为·harmonyos·鸿蒙系统·arkui·huawei
橙子199110168 小时前
在 Kotlin 中什么是委托属性,简要说说其使用场景和原理
android·开发语言·kotlin
androidwork8 小时前
Kotlin Android LeakCanary内存泄漏检测实战
android·开发语言·kotlin
笨鸭先游9 小时前
Android Studio的jks文件
android·ide·android studio
gys98959 小时前
android studio开发aar插件,并用uniapp开发APP使用这个aar
android·uni-app·android studio
H309199 小时前
vue3+dhtmlx-gantt实现甘特图展示
android·javascript·甘特图
像风一样自由9 小时前
【001】renPy android端启动流程分析
android·gitee
千里马学框架11 小时前
重学安卓14/15自由窗口freeform企业实战bug-学员作业
android·framework·bug·systrace·安卓framework开发·安卓窗口系统·自由窗口
xianrenli3816 小时前
android特许权限调试
android
*拯19 小时前
Uniapp Android/IOS 获取手机通讯录
android·ios·uni-app