【问题标题】:How to access the field of top-level object?如何访问顶级对象的字段?
【发布时间】:2021-08-07 15:56:27
【问题描述】:

当我这样做时

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 不允许我使用顶级对象的属性?我认为object 就像类对象一样,但是匿名(没有类)并且在上面的示例中datadata7 之间应该没有区别。不过好像有区别。

【问题讨论】:

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

标签: kotlin


【解决方案1】:

这在Language Specification 的“对象文字”部分中记录了,关于对象声明和匿名对象(对象文字创建的东西)之间的区别。

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

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

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

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

当匿名对象类型的值超出当前范围时:

  • 如果该类型只有一个声明的超类型,它会隐式向下转换为这个声明的超类型;
  • 如果该类型有多个声明的超类型,则必须隐式或显式强制转换为范围外可见的任何合适类型,否则会出现编译时错误。

这里,超类型隐式为Any,所以data的类型为Any,显然Any类型上没有field

另一方面,data4 没有转义当前范围,因为它是 main 函数语句范围的本地。您无法从其他范围访问它。

另请参阅规范中的出色示例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-03
    • 1970-01-01
    • 2012-08-02
    • 1970-01-01
    • 1970-01-01
    • 2023-01-09
    • 1970-01-01
    相关资源
    最近更新 更多