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:隐式配置对象属性,强调初始化。
相关推荐
啦啦91171413 分钟前
Niagara Launcher 全新Android桌面启动器!给手机换个门面!
android·智能手机
游戏开发爱好者815 分钟前
iOS 上架要求全解析,App Store 审核标准、开发者准备事项与开心上架(Appuploader)跨平台免 Mac 实战指南
android·macos·ios·小程序·uni-app·iphone·webview
xrkhy18 分钟前
canal1.1.8+mysql8.0+jdk17+redis的使用
android·redis·adb
00后程序员张1 小时前
混淆 iOS 类名与变量名的实战指南,多工具组合把混淆做成工程能力(混淆 iOS 类名变量名/IPA 成品混淆Ipa/Guard CLI 实操)
android·ios·小程序·https·uni-app·iphone·webview
介一安全2 小时前
【Frida Android】实战篇1:环境准备
android·网络安全·逆向·frida
许愿OvO3 小时前
MySQL触发器
android·mysql·adb
循环不息优化不止3 小时前
Jetpack Compose 从重组到副作用的全方位解析
android
2501_916007474 小时前
iOS文件管理工具深度剖析,从系统沙盒到跨平台文件操作的多工具协同实践
android·macos·ios·小程序·uni-app·cocoa·iphone
Android疑难杂症5 小时前
鸿蒙Notification Kit通知服务开发快速指南
android·前端·harmonyos
lcanfly5 小时前
Mysql作业5
android·数据库·mysql