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:隐式配置对象属性,强调初始化。
相关推荐
雨白4 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
kk爱闹6 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空7 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭8 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日9 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安9 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑9 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟13 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡14 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi0014 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体