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

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

先来看一个简单的示例:

fun test(): String {
    val s: String = "asdf".also {
        println(it.length)
    }
    return s
}

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

然后第2个示例:

fun test(): String {
    val s: String = "asdf".apply {
        println(length)
    }
    return s
}

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

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

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

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

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

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来引用对象的成员,来减少遮蔽想象的发生,方便阅读,例如:
fun test(): String {
    val length = 1
    val s: String = "asdf".apply {
        println(this.length)
    }
    return s
}
  1. 避免不同上下文中同名变量的使用。(包括开发者定义的变量和隐式的it
  2. 标准库中的能满足或普通函数就能满足,尽量避免自定义一些作用域函数。
  3. 团队中如果不可避免地自定义/扩展了作用域函数,就保持api的稳定,并完善相关文档说明和规范(比如,“新的自定义作用域函数禁止引入对象上下文”或对名称进行规范)

相关推荐

  1. Kotlin作用函数引发遮蔽问题

    2024-04-26 15:38:03       12 阅读
  2. Kotlin 作用函数

    2024-04-26 15:38:03       44 阅读
  3. Kotlin作用函数

    2024-04-26 15:38:03       37 阅读
  4. Kotlin it隐式变量遮蔽问题

    2024-04-26 15:38:03       14 阅读
  5. Kotlin also 和 run:选择正确作用函数

    2024-04-26 15:38:03       33 阅读
  6. Kotlin 作用函数:理解 apply, let, 和 with

    2024-04-26 15:38:03       30 阅读
  7. Kotlin作用函数:let、also、run、apply、with

    2024-04-26 15:38:03       15 阅读
  8. Kotlin->Kotlin协程作用

    2024-04-26 15:38:03       14 阅读
  9. 函数名称空间与作用

    2024-04-26 15:38:03       39 阅读
  10. 函数作用

    2024-04-26 15:38:03       11 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-26 15:38:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-26 15:38:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-26 15:38:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-26 15:38:03       18 阅读

热门阅读

  1. Go语言第二篇-基本数据类型与转义字符

    2024-04-26 15:38:03       12 阅读
  2. 多路IO复用--epoll

    2024-04-26 15:38:03       23 阅读
  3. python笔记(15)函数

    2024-04-26 15:38:03       26 阅读
  4. WPF之RadioButton单选框和checkbox多选框

    2024-04-26 15:38:03       15 阅读