【问题标题】:Access the definition body of symbols访问符号的定义体
【发布时间】:2014-05-08 14:00:03
【问题描述】:

如何从宏中查看符号的定义?

作为一种特殊情况,我想知道如何在编译时使用宏来评估常量值。 我的方法适用于“最终 val”,但不适用于本地“val”:

// scalaVersion := "2.11.0"
import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros

object Const {
  def m_same(c: Context)(i: c.Tree) = {
    import c.universe._
    val Literal(Constant(_)) = i
    i
  }
  def same(i: Any): Any = macro m_same
}

本地值未被识别为Literal(Constant(_))

import org.scalatest.FreeSpec

class ConstSpec extends FreeSpec {
  "Int literal" in {
    assert(Const.same(42) === 42)
  }

  final val iFinal = "mytest"            // is a Literal(Constant(_))
  "final Int value" in {
    assert(Const.same(iFinal) === iFinal)
  }

  "local Int value" in {
    val iLocal = 42                       // is NOT a Literal(Constant(_))
    assert(Const.same(iLocal) === iLocal) // does NOT compile
  }
}

【问题讨论】:

    标签: scala reflection macros scala-macros


    【解决方案1】:

    final val 对常量有特殊意义,意味着内联。

    你的普通 val 看起来像:

    scala> q"{ val i = 42 ; i }"
    res0: reflect.runtime.universe.Tree =
    {
      val i = 42;
      i
    }
    
    scala> showRaw(res0)
    res1: String = Block(List(ValDef(Modifiers(), TermName("i"), TypeTree(), Literal(Constant(42)))), Ident(TermName("i")))
    

    我认为 Travis Brown 的 Metaplasm 博客,即你不应该在家尝试使用宏的事情,包括检查周围上下文的定义。

    在这种情况下,根据语句查询封闭上下文会发现您想要的 i 的定义,并且您可以检查它的 RHS。

    他们的宏观理念是本地思考和本地扩展。我只是编造的。他们还为同伴等不太本地化的事物提供宏注释。

    但是等等,他们确实在Context 上提供了eval 设施。这足以满足您的用例吗?

    【讨论】:

    • 这对我的问题来说是一个很好的答案。谢谢你。实际上,我并没有真正需要检查符号体,但我已经通过尝试获得我的“恒定值”来考虑它。我需要的上下文是一个具有变化行为的宏,它取决于作为参数给出的常量值,特别是生成一个 DataContaining 实例或一个应该在编译时决定的特征的 Empty 实例。我已经知道的另一种可能性是给出不同类型的参数并检查宏内的类型。
    猜你喜欢
    • 2011-01-13
    • 1970-01-01
    • 1970-01-01
    • 2013-04-15
    • 1970-01-01
    • 2020-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多