10

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

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

4

2 回答 2

5

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

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

它在打字机中定制的一件事是:

override def canAdaptConstantTypeToLiteral = false

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

开头的大评论adapt说这是它做的第一件事,或者更确切地说,它在 scaladocking 时不做的第零件事。

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

只是为了好玩,我会尝试翻转旗帜,看看会发生什么。(编辑:scala 文档构建良好。该标志源于演示编译器行为,但对我来说它如何应用于 scaladoc 并不明显。)

于 2013-11-18T00:38:08.150 回答
4

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

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

对于 Matt Malone,您不会看到 StaticAnnotation 中的“注释参数需要是一个常量”,因为它不会强制执行类似的操作。这编译,没有警告。

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
***/
于 2013-11-16T06:30:53.607 回答