为什么下面的代码会打印0

class X {
    fun f() {
        val x = 0
        val a = object {
            val x = 1
            fun g() {
                println(x)
            }
        }
        a.g()
    }
}

fun main() {
    val x = X()
    x.f()
}

为什么内部属性声明不会遮蔽外部属性声明?


最佳答案
1

对于非限定名称,本地可调用(即域内的声明)始终优先于非本地可调用。“内部作用域中的内容隐藏外部作用域中的内容”规则紧随其后

规范的

对于名为的标识符,f将分析以下集合(按给定的顺序):

  1. f当前范围及其向上链接范围中命名的本地非扩展可调用函数,按范围的大小排序(从小到大),不包括包范围;
  2. 按照接收器优先级的顺序e,对d当前范围内可用的每对隐式接收器的过载候选集进行计算,就好像是显式接收器一样;e
  3. [与本场景无关]

步骤 1 考虑所有本地可调用函数,然后我们才会在第二步中尝试使用接收器的可调用函数。

将其应用到您的代码中,

fun f() {
    val x = 0 // This 'x' is local to 'f'
    val a = object {
        val x = 1 // This 'x' is not local. The body of an object literal is a declaration scope, not a statement scope
        fun g() {
            println(x)
        }
    }
    a.g()
}

x如果不像这样优先考虑当地人,那么当你在 时,你就无法提到当地人g

7

  • 他们选择这样的作用域规则有什么原因吗?对于块状词法作用域来说,这是违反直觉的,你会期望内部事物掩盖外部事物。


    – 


  • @Wickoo 如果x本身访问对象的属性,那么您将如何访问主体中的x本地?您可能会发明一些新的语法并引入更多复杂性,但如果引用本地,则没有必要,因为您已经可以使用 引用对象的属性fgxxthis.x


    – 


  • 我猜这正是 Kotlin 设计师面临的问题。我会让x其绑定字段,而不是让其访问外部字段。x在 Java 中,您如何访问外部字段?“` void f() { int x = 0; class A { int x = 1; void g() { System.out.println(x); } } A a = new A(); ag(); }“`


    – 

  • @Wickoo 我不认为你能用 Java 做到这一点…这就是为什么 Kotlin 更好:)


    – 

  • 2
    @Wickoo 不,非限定名称首先针对本地进行解析。如果没有匹配,请尝试隐式接收器(即 implied this)。本地是在语句范围(可以放置语句的范围,如for循环)中声明的内容。


    –