提问人:gstackoverflow 提问时间:6/29/2023 更新时间:6/29/2023 访问量:126
为什么我无法访问 Kotlin 中匿名对象的非私有成员?
Why do I can't access to non-private member of anonymous object in Kotlin?
问:
我是一名 Java 开发人员,现在我正在学习 Kotlin。
我遇到了一段有趣的(工作)代码:
class C {
private fun getObject() = object {
val x: String = "x"
}
fun printX() {
println(getObject().x)
}
}
但是,如果我删除方法的修饰符:private
getObject
class C {
fun getObject() = object {
val x: String = "x"
}
fun printX() {
println(getObject().x)
}
}
Kotlin 抱怨
Unresolved reference: x
你能解释一下为什么这样做吗?从我的角度来看,它看起来有点奇怪。
答:
为什么它不起作用?
这是因为我们创建了一个匿名对象/类,因此它在用户可用的类型系统中没有表示形式。没有带属性的类,我们只能将这个对象表示为 。当然,编译器在内部会创建一个带有 的类,但是这个类对我们来说是不可见的,我们不能将此类对象及其真实类型存储在属性中,等等。x
Any
x
那么为什么它确实有效呢?
Kotlin 和其他一些语言有时会为本地代码提供“超能力”。这方面有多个例子:
- Kotlin:如上所述,访问成员,但前提是私有。
object
- Kotlin:属性的智能转换,但前提是在本地模块中。
- Java:类型推断,但仅适用于局部变量。
- Kotlin/Java:交集类型,但仅适用于局部变量。
- Kotlin/Java:访问嵌套/外部类的私有字段。
很难提供一个简单的答案来解释我们为什么要这样做。但一般来说,当我们处理本地或私有代码时,我们会关注这个小的功能片段,我们考虑文件或类的实现细节。然后,我们通常更喜欢方便和隐含,而不是保持代码的严格和明确。如果我们必须改变任何事情,我们会在一个地方完成。
如果组件是公共的,则相反。在这种情况下,它们可以在代码周围的几十个地方使用,我们无法记住它们,因此如果我们保持代码更严格,维护起来会更安全、更容易,例如创建一个常规的命名类而不是匿名类。
如果从另一个模块访问代码,情况会更糟。在这种情况下,编译器不知道原始代码的完整上下文,它只看到一个返回具有某个随机名称的类的方法。Kotlin 可以通过使用注释在字节码中添加额外的信息,但 Java/JavaScript 会完全忽略它们。此外,由于我们没有为匿名类提供名称,编译器必须自动生成它。如果它将来会生成不同的名称,那将是二进制不兼容的更改。
另一个可能的原因是编译器的复杂性。为了实现这些功能,编译器必须保留有关代码的附加元数据,并且必须应用一些技巧来“打破规则”。如果只允许在本地进行,编译器可以一次对单个文件/类/模块执行这些复杂的转换,但通常保持更简单的代码表示形式。
评论
open