Ed *_*aub 9 scala scala-macros
鉴于知道算术final val表达式是否会被编译为编译时常量是多么困难,以及意外破坏编译时间是多么容易 ......
在编译时,有没有人能想到一种简单的方法来验证编译器是否实际上从一个复杂的算术表达式创建了一个编译时常量?我猜这可能是某种注释或宏,但也许有一些更简单的东西.例如,可能是这样的:
@CompileTime final val HALF_INFINITY = Int.MaxValue / 2
Run Code Online (Sandbox Code Playgroud)
是可能的.
Eug*_*ako 10
幸运的是,宏被连接到类型检查(在宏扩展之前宏观参数被强调),并且类型检查折叠常量,因此看起来应该足以Literal(Constant(_))在宏中检查以确保宏的参数是不变.
注意.在宏观天堂中实现的宏注释在注释的类型检查之前扩展,这意味着它们的参数在扩展期间不会被包围,使得宏注释成为执行该任务的不太方便的工具.
这是使用Scala 2.11.0-M8语法为def宏编写的代码.对于2.11.0-M7,请将导入替换为import scala.reflect.macros.{BlackboxContext => Context}.对于2.10.x,替换导入import scala.reflect.macros.Context,重写impl要读取def impl[T](c: Context)(x: c.Expr[T]) = ...的签名和ensureConstant要读取的签名def ensureConstant[T](x: T): T = macro impl[T].
// Macros.scala
import scala.reflect.macros.blackbox._
import scala.language.experimental.macros
object Macros {
def impl(c: Context)(x: c.Tree) = {
import c.universe._
x match {
case Literal(Constant(_)) => x
case _ => c.abort(c.enclosingPosition, "not a compile-time constant")
}
}
def ensureConstant[T](x: T): T = macro impl
}
// Test.scala
import Macros._
object Test extends App {
final val HALF_INFINITY = ensureConstant(Int.MaxValue / 2)
final val HALF_INFINITY_PLUS_ONE = ensureConstant(HALF_INFINITY + 1)
final val notConst = ensureConstant(scala.util.Random.nextInt())
}
00:26 ~/Projects/Master/sandbox (master)$ scalac Macros.scala && scalac Test.scala
Test.scala:6: error: not a compile-time constant
final val notConst = ensureConstant(scala.util.Random.nextInt())
^
one error found
Run Code Online (Sandbox Code Playgroud)