为什么 Kotlin 枚举属性不是编译时常量?

fra*_*eff 3 enums kotlin

这个问题的主要目标是理解实现以及为什么会这样。当然,它的解决方案或解决方法也将受到高度赞赏......

给出这个例子:

enum class SomeEnum(val customProp: String) {
  FOO("fooProp"),
  BAR("barProp");
}

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.SOURCE)
annotation class TheAnnotation(
  val targetValue: String
)

@TheAnnotation(targetValue = SomeEnum.FOO.customProp)
fun testFun() {
  
}

Run Code Online (Sandbox Code Playgroud)

编译结果出现以下错误:

SomeEnum.kt: (14, 30):注释参数必须是编译时常量

由于显而易见的原因,注释值(以及其他值)必须是编译时常量,这在许多不同方面都是有意义的。我不清楚的是为什么customProp编译器不将其视为常量。

如果枚举被定义为有限的、封闭的信息集,那么根据我的理解,它们应该只在编译时可变,即“编译时常量”。对于枚举在 Kotlin 运行时可以以某种方式进行修改的不太可能的情况,这也可以回答这个问题。

附录:

枚举值(例如SomeEnum.FOO)实际上被视为编译时常量。证据是,以下稍作修改的代码片段可以编译:

enum class SomeEnum(val customProp: String) {
  FOO("fooProp"),
  BAR("barProp");
}

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.SOURCE)
@MustBeDocumented
annotation class TheAnnotation(
  val targetValue: SomeEnum
)

@TheAnnotation(targetValue = SomeEnum.FOO)
fun testFun() {

}
Run Code Online (Sandbox Code Playgroud)

Swe*_*per 5

枚举被定义为有限的、封闭的信息集,根据我的理解,它们应该只在编译时可变

事实上,没有。枚举类只是一种特殊的类,它不允许您创建除声明中命名的实例之外的任何新实例,以及更多语法糖。因此,像常规类一样,它可以具有值仅在运行时已知的属性,以及可变的属性(尽管这通常是一个非常糟糕的主意)。

例如:

enum class Foo {
    A, B;

    val foo = System.currentTimeMillis() // you can't know this at compile time!
}
Run Code Online (Sandbox Code Playgroud)

这基本上脱糖为:

class Foo private constructor(){
    val foo = System.currentTimeMillis()
    companion object {
        val A = Foo()
        val B = Foo()
    }
}
Run Code Online (Sandbox Code Playgroud)

(实际生成的代码比这个多了一点,但这足以说明我的观点)

AB只是 的两个(也是唯一的两个)实例Foo。很明显,这Foo.A不是编译时常量*,更不用说Foo.A.foo。您可以添加一个initFoo来运行任意代码。你甚至可以制作foo一个var,让你可以做一些可怕的事情,例如:

Foo.A.foo = 1
// now every other code that uses Foo.A.foo will see "1" as its value
Run Code Online (Sandbox Code Playgroud)

您可能还想知道为什么他们没有实现一个更受限制的枚举,该枚举不允许您执行这些操作,并且一个编译时间常量,但这是一个不同的问题

另请参阅:语言规范


*尽管您仍然可以传递Foo.A注释。对于注释来说,Foo.A是一个编译时常量,因为注释所要做的就是存储名称“Foo.A”,而不是它引用的对象,该对象必须在运行时计算。

  • `Foo.A` 也不是编译时常量。请参阅规范的[本节](https://kotlinlang.org/spec/expressions.html#exhaustive-when-expressions)。这是一种特殊情况,它可以用作注释参数。 (3认同)