如何访问顶级对象的字段?

How to access the field of top-level object?

提问人:Dmitrii Rashchenko 提问时间:8/7/2021 更新时间:8/7/2021 访问量:539

问:

当我这样做时

val data = object {
    val field = 5
}

fun main(){
    println(data.field)  // throws
}

它抛出.Unresolved reference: field

但这一切都没关系:

val field = 6

class Data(val field: Int = 7)
val data7 = Data()

fun main(){
    val data4 = object {
        val field = 4
    }
    println(field)  // ok
    println(data4.field)  // ok
    println(data7.field)  // ok
}

我不明白,为什么 Kotlin 不允许我使用顶级对象的属性?我认为这就像类对象一样,但匿名(没有类),并且在上面的示例中和之间应该没有区别。但似乎有区别。objectdatadata7

科特林

评论

2赞 gidds 8/7/2021
严格来说,“未解析的引用:字段”不会被“抛出”,因为它并不例外:这是一个编译时错误,由编译器由于无效代码而生成。当有效代码遇到无法处理的情况时,会在运行时引发异常。

答:

8赞 Sweeper 8/7/2021 #1

这记录在语言规范的“对象文本”部分,其中介绍了对象声明和匿名对象(对象文本创建的内容)之间的区别。

常规对象声明和匿名对象之间的主要区别在于其类型。匿名对象的类型是一种特殊的类型,只有在声明它的作用域中才可用(和可见)。它类似于常规对象声明的一种类型,但是,由于它不能在声明范围之外使用,因此具有一些有趣的效果。

你的这里被认为已经逃脱了“文件的顶层”的声明范围,因为它是公开的。您可以从其他文件的顶级范围访问它。data

注意:在此上下文中,如果将相应的值声明为非私有全局或分类器范围属性,则会立即执行“转义当前范围”,因为这些属性是外部可访问接口的一部分。

标记它会修复它。错误的原因是:private

当匿名对象类型的值转义当前作用域时:

  • 如果该类型只有一个声明的超类型,则将其隐式向下转换为此声明的超类型;
  • 如果该类型具有多个声明的超类型,则必须对作用域外可见的任何合适类型进行隐式或显式强制转换,否则就是编译时错误。

这里超类型是隐式的,所以类型是,显然类型上没有。AnydataAnyfieldAny

另一方面,have 没有转义当前作用域,因为它是函数的语句作用域的局部作用域。无法从其他作用域访问它。data4main

另请参阅规范中的优秀示例。