为什么我不能访问Kotlin中匿名对象的非私有成员?

pftdvrlh  于 2023-06-30  发布在  Kotlin
关注(0)|答案(1)|浏览(115)

我是一名Java开发人员,现在正在学习Kotlin。
我遇到了一段有趣的(工作)代码:

class C {
    private fun getObject() = object {
        val x: String = "x"
    }

    fun printX() {
        println(getObject().x)
    }
}

但是如果我删除getObject方法的private修饰符:

class C {
    fun getObject() = object {
        val x: String = "x"
    }

    fun printX() {
        println(getObject().x)
    }
}

Kotlin抱怨

Unresolved reference: x

你能解释一下为什么要这样做吗?从我的Angular 来看,它看起来有点奇怪。

8e2ybdfx

8e2ybdfx1#

”为什么它不工作?**
这是因为我们创建了一个匿名对象/类,所以它在类型系统中没有对用户可用的表示。没有具有x属性的类,我们只能将此对象表示为Any。当然,编译器在内部创建了一个带有x的类,但是这个类对我们来说是不可见的,我们不能在属性中存储这样的对象及其真实的类型。
”为什么它工作吗?**
Kotlin和其他一些语言有时会为本地代码提供“超能力”。这方面有多个例子:

  • Kotlin:如上所述,访问object成员,但仅限于私有成员。
  • Kotlin:智能转换属性,但仅在本地模块中。
  • Java:类型推断,但仅适用于局部变量。
  • Kotlin/Java:交叉点类型,但仅适用于局部变量。
  • Kotlin/Java:访问嵌套/外部类的私有字段。

很难简单地回答我们为什么这样做。但是一般来说,当我们处理本地或私有代码时,我们关注的是这个小的功能片段,我们考虑文件或类的实现细节。那么我们通常更喜欢方便和隐式,而不是保持代码严格和显式。如果我们必须改变什么,我们在一个地方这样做。
如果组件是公共的,则相反。在这种情况下,它们可以在代码周围的几十个地方使用,我们不能记住所有的地方,所以如果我们保持我们的代码更严格,那么它更安全,更容易维护。创建一个常规的命名类而不是匿名类。
如果从另一个模块访问代码,情况甚至更糟。在这种情况下,编译器不知道原始代码的完整上下文,它只看到一个方法返回一个具有随机名称的类。Kotlin可以通过使用注解在字节码中添加额外的信息,但Java/JavaScript会完全忽略它们。另外,由于我们没有为匿名类提供名称,编译器必须自动生成它。如果它将来会生成一个不同的名称,那将是一个二进制不兼容的更改。
另一个潜在的原因是编译器的复杂性。为了允许这样的功能,编译器必须保留关于代码的附加元数据,并且必须应用一些技巧来“打破规则”。如果只允许在本地执行,编译器可以一次为单个文件/类/模块执行这些复杂的转换,但通常保持更简单的代码表示。

相关问题