首页 > 解决方案 > 如何访问顶级对象的字段?

问题描述

当我这样做时

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就像类对象一样,但是匿名(没有类),data并且data7上面的示例之间应该没有区别。但似乎有区别。

标签: kotlin

解决方案


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

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

您的data此处被认为已超出“文件顶层”的声明范围,因为它是公开的。您可以从其他文件的顶级范围访问它。

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

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

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

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

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

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

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


推荐阅读