我是一名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 来看,它看起来有点奇怪。
1条答案
按热度按时间8e2ybdfx1#
”为什么它不工作?**
这是因为我们创建了一个匿名对象/类,所以它在类型系统中没有对用户可用的表示。没有具有
x
属性的类,我们只能将此对象表示为Any
。当然,编译器在内部创建了一个带有x
的类,但是这个类对我们来说是不可见的,我们不能在属性中存储这样的对象及其真实的类型。”为什么它工作吗?**
Kotlin和其他一些语言有时会为本地代码提供“超能力”。这方面有多个例子:
object
成员,但仅限于私有成员。很难简单地回答我们为什么这样做。但是一般来说,当我们处理本地或私有代码时,我们关注的是这个小的功能片段,我们考虑文件或类的实现细节。那么我们通常更喜欢方便和隐式,而不是保持代码严格和显式。如果我们必须改变什么,我们在一个地方这样做。
如果组件是公共的,则相反。在这种情况下,它们可以在代码周围的几十个地方使用,我们不能记住所有的地方,所以如果我们保持我们的代码更严格,那么它更安全,更容易维护。创建一个常规的命名类而不是匿名类。
如果从另一个模块访问代码,情况甚至更糟。在这种情况下,编译器不知道原始代码的完整上下文,它只看到一个方法返回一个具有随机名称的类。Kotlin可以通过使用注解在字节码中添加额外的信息,但Java/JavaScript会完全忽略它们。另外,由于我们没有为匿名类提供名称,编译器必须自动生成它。如果它将来会生成一个不同的名称,那将是一个二进制不兼容的更改。
另一个潜在的原因是编译器的复杂性。为了允许这样的功能,编译器必须保留关于代码的附加元数据,并且必须应用一些技巧来“打破规则”。如果只允许在本地执行,编译器可以一次为单个文件/类/模块执行这些复杂的转换,但通常保持更简单的代码表示。