Scala常量表达式和计算字符串文字

时间:2013-11-12 20:02:45

标签: scala

我在使用Java注释时遇到了一些棘手的问题,并且规定他们的参数必须是“常量”。 Scala 2.8语言规范的6.24规定“常量表达式”是以下任何一种(强调我的):

  • 值类的文字,例如整数
  • 字符串文字
  • 使用Predef.classOf(§12.5)
  • 构建的类
  • 来自底层平台的枚举元素
  • 一个文字数组,格式为Array(c1,...,cn),其中所有的ci都是它们自己 常量表达
  • 由恒定值定义(第4.1节)定义的标识符。

现在,“字符串文字”似乎是以这样的方式定义的,它实际上只是一个“”或“”“”“”分隔的字符块,这是非常明确的。那么,我的问题是给出

的原因
object MyObject {
  final val MY_CONSTANT1="foo"
  final val MY_CONSTANT2="bar" + "baz"
  final val MY_CONSTANT3="qux" + "quux" + "frobozz"
}

// ...

@MyAnnotation( ??? )
def Foo(): Unit {
...

@MyAnnotation编译和scaladocs与MY_CONSTANT1和MY_CONSTANT2,但不是MY_CONSTANT3(我得到“注释参数需要是常量”)。为什么MY_CONSTANT2可以工作?在工作中是否有一些未指定的最多两个字符串 - 文字 - 可以组合成一个更大的规则,还是我疯了?

编辑我正在使用Scala 2.10,它似乎修复了早期Scala版本中与注释相关的编译器错误。

2 个答案:

答案 0 :(得分:5)

你说它是“编译和scaladocs”,所以我猜你的错误就是当你运行scaladoc时,就像我一样。

使用scaladoc,您将获得一个仅运行到typer阶段的专用编译器。

其定制的东西之一是:

override def canAdaptConstantTypeToLiteral = false

将其更改为true,您的简单示例将为scaladoc。

adapt开头的重要评论说这是它做的第一件事,或者更确切地说,是scaladocking时它没有做的第0件事。

*  (0) Convert expressions with constant types to literals (unless in interactive/scaladoc mode)

只是为了好玩,我会试着翻看旗帜,看看有什么打破。 (编辑:scala文档构建正常。标志源于演示编译器行为,但对我来说,它对scaladoc的适用程度并不明显。)

答案 1 :(得分:4)

所有这些字符串都以相同的方式编译 - 它们都被折叠成单个文字。您可以在字节码中看到它们。

0: ldc           #19                 // String foo
0: ldc           #22                 // String barbaz
0: ldc           #24                 // String quxquuxfrobozz

对Matt Malone来说,静态注释不会看到“注释参数必须是常量”,因为它不会强制执行任何类似的操作。编译,没有警告。

class MyAnnotation(val s: String) extends scala.annotation.StaticAnnotation
object MyObject {
  def inconstant(): String = scala.util.Random.nextString(10)
  @MyAnnotation(s = inconstant) def f = null
}

诱导“注释参数需要是常量”的方法是首先扩展ClassfileAnnotation,然后执行一些阻止val具有常量类型的操作。像这样的东西。类型归因导致MY_CONSTANT1具有String类型而不是常量类型String(“foo”)。你不能直接在scala中表达常量类型,但这就是它在内部表示的方式。

class MyAnnotation(val s: String) extends scala.annotation.ClassfileAnnotation
object MyObject {
  final val MY_CONSTANT1: String = "foo" 
  final val MY_CONSTANT2 = "bar" + "baz"
  final val MY_CONSTANT3 = "qux" + "quux" + "frobozz"
}
object Bippy {
  @MyAnnotation(s = MyObject.MY_CONSTANT1) def f1 = null
  @MyAnnotation(s = MyObject.MY_CONSTANT2) def f2 = null
  @MyAnnotation(s = MyObject.MY_CONSTANT3) def f3 = null
}

/***
a.scala:8: error: annotation argument needs to be a constant; found: MyObject.MY_CONSTANT1
  @MyAnnotation(s = MyObject.MY_CONSTANT1) def f1 = null
                             ^
one warning found
one error found
***/