Kotlin作用域函数引发的遮蔽问题

前面讲了kotlin的it变量引起的遮蔽问题,见Kotlin it隐式变量的遮蔽问题,本篇聊聊作用域函数(scoped function)可能引起的遮蔽问题。

先来看一个简单的示例:

kotlin 复制代码
fun test(): String {
    val s: String = "asdf".also {
        println(it.length)
    }
    return s
}

这里涉及3个上下文:全局上下文、test函数局部上下文、also引入的上下文。

然后第2个示例:

kotlin 复制代码
fun test(): String {
    val s: String = "asdf".apply {
        println(length)
    }
    return s
}

不过这里涉及4个上下文:全局上下文、test函数局部上下文、apply引入的大括号之间的上下文,以及调用apply的字符串对象的对象上下文。

两段程序极为相似,在词法和语法结构上光靠肉眼难以发现差异,但上下文环境却有着较大的差别。在我第一次学习到Kotlin的这个特性时,心里有些不安。

传统的函数式语言中,如Lisp,在使用类似Lambda表达式之类的匿名函数时会引入新的上下文,Java也同理,但不会引入新的对象上下文(Java要同时引入新的函数和对象上下文需要用匿名内部类)。而局部匿名函数在Kotlin中也会引入这个新的函数上下文,却可能引入一个隐式的对象上下文。而这个对象上下文能否观察到、是否醒目就取决于编辑器的提示了。

Kotlin中这样的设计可以让代码变得简洁,但有点过于简洁了,省略了一些有助于阅读的信息,在发生遮蔽的时候有些代码可能反而没有那么直观,比如:

kotlin 复制代码
fun test(): String {
    val length = 1
    val s: String = "asdf".apply {
        println(length) // length ?
    }
    return s
}

kotlin 复制代码
class Test {
    val length = 1
    fun test(): String {
        val s: String = "asdf".apply {
            println(length) // length ?
        }
        return s
    }
}

大家可以看出println(length)中的length分别指向哪个对象吗?

所以,我认为作用域函数中引入对象的上下文,有利于简化代码的编写,但是因为其可能导致不易察觉的隐式遮蔽,所以对阅读可能造成影响。甚至,如果经常复制粘贴代码或编写长篇大段的代码,在功能迭代更新时可能因为没有注意到遮蔽的发生而导致bug。

一点点建议

  1. 在使用作用域函数(scoped function)时尽量避免多层嵌套,尤其是多个作用域函数嵌套。(一种较为消极且安全的方式)
  2. 在引入对象上下文的作用域函数(例如apply)中使用this来引用对象的成员,来减少遮蔽想象的发生,方便阅读,例如:
kotlin 复制代码
fun test(): String {
    val length = 1
    val s: String = "asdf".apply {
        println(this.length)
    }
    return s
}
  1. 避免不同上下文中同名变量的使用。(包括开发者定义的变量和隐式的it
  2. 标准库中的能满足或普通函数就能满足,尽量避免自定义一些作用域函数。
  3. 团队中如果不可避免地自定义/扩展了作用域函数,就保持api的稳定,并完善相关文档说明和规范(比如,"新的自定义作用域函数禁止引入对象上下文"或对名称进行规范)
相关推荐
モンキー・D・小菜鸡儿11 小时前
Android 中 StateFlow 的使用
android·kotlin
我又来搬代码了11 小时前
【Android】【Compose】Compose知识点复习(一)
android·前端·kotlin·android studio
hnlgzb16 小时前
好像kotlin class和kotlin file都可以是activity?
android·开发语言·kotlin
zhangphil16 小时前
Kotlin超时withTimeout超时与ensureActive()取消协程任务执行
kotlin
hnlgzb1 天前
安卓app开发,如何快速上手kotlin和compose的开发?
android·开发语言·kotlin
alexhilton1 天前
Jetpack Compose 2025年12月版本新增功能
android·kotlin·android jetpack
lin62534222 天前
Android九宫格,1张图到9张图适配;图片自定义UI
android·ui·kotlin
zhangphil2 天前
Kotlin协程buffer缓冲池,调度任务执行
kotlin
モンキー・D・小菜鸡儿2 天前
Android Jetpack Compose 基础控件介绍
android·kotlin·android jetpack·compose
侠***I2 天前
基于OOA-TCN-BiGRU-Attention的鱼鹰算法优化多变量时间序列预测
kotlin