有没有办法在编译时测试一个常量是编译时常量? [英] Is there a way to test at compile-time that a constant is a compile-time constant?

查看:55
本文介绍了有没有办法在编译时测试一个常量是编译时常量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

鉴于 了解算术是否为 final val 是多么困难表达式将被编译为编译时常量,意外破坏编译时性是多么容易...

Given how difficult it is to know whether an arithmetic final val expression will be compiled to a compile-time constant, and how easy it is to accidentally break compile-time-ness...

谁能想出一种简单的方法来在编译时验证编译器是否确实从复杂的算术表达式创建了一个编译时常量?我猜这可能是某种注释或宏,但也许有更简单的东西.例如,可能类似于:

Can anyone think of an easy way to verify, at compile-time, that the compiler has actually created a compile-time constant from, say, a complex arithmetic expression? I'm guessing this might be some kind of annotation or macro, but maybe there's something simpler. For example, maybe something like:

   @CompileTime final val HALF_INFINITY = Int.MaxValue / 2

有可能.

推荐答案

幸运的是,宏被连接到类型检查中(从某种意义上说,宏参数在宏扩展之前被类型检查),并且类型检查折叠常量,所以它看起来像应该足以检查宏中的 Literal(Constant(_)) 以确保宏的参数是常量.

Luckily enough, macros are wired into typechecking (in the sense that macro arguments are typechecked prior to macro expansion), and typechecking folds constants, so it looks like it should be sufficient to check for Literal(Constant(_)) in a macro to make sure that macro's argument is a constant.

注意.在宏天堂中实现的宏注释在注释者的类型检查之前扩展,这意味着它们的参数在扩展过程中不会被constfold,使得宏注释不太方便执行此任务.

Note. Macro annotations implemented in macro paradise expand prior to typechecking of the annottees, which means that their arguments won't be constfolded during the expansion, making macro annotations a less convenient vehicle for carrying out this task.

这是使用 Scala 2.11.0-M8 语法为 def 宏编写的代码.对于 2.11.0-M7,将导入替换为 import scala.reflect.macros.{BlackboxContext =>上下文}.对于2.10.x,将import替换为import scala.reflect.macros.Context,重写impl的签名,读取def impl[T](c:Context)(x: c.Expr[T]) = ...ensureConstant 的签名来读取 def ensureConstant[T](x: T): T =宏 impl[T].

Here's the code written with Scala 2.11.0-M8 syntax for def macros. For 2.11.0-M7, replace the import with import scala.reflect.macros.{BlackboxContext => Context}. For 2.10.x, replace the import with import scala.reflect.macros.Context, rewrite the signature of impl to read def impl[T](c: Context)(x: c.Expr[T]) = ... and the signature of ensureConstant to read 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

这篇关于有没有办法在编译时测试一个常量是编译时常量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆