这个问题的主要目标是理解实现以及为什么会这样。当然,它的解决方案或解决方法也将受到高度赞赏......
给出这个例子:
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)
枚举被定义为有限的、封闭的信息集,根据我的理解,它们应该只在编译时可变
事实上,没有。枚举类只是一种特殊的类,它不允许您创建除声明中命名的实例之外的任何新实例,以及更多语法糖。因此,像常规类一样,它可以具有值仅在运行时已知的属性,以及可变的属性(尽管这通常是一个非常糟糕的主意)。
例如:
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)
(实际生成的代码比这个多了一点,但这足以说明我的观点)
A和B只是 的两个(也是唯一的两个)实例Foo。很明显,这Foo.A不是编译时常量*,更不用说Foo.A.foo。您可以添加一个init块Foo来运行任意代码。你甚至可以制作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”,而不是它引用的对象,该对象必须在运行时计算。
| 归档时间: |
|
| 查看次数: |
1468 次 |
| 最近记录: |