在运行时获取Scala变量名称

时间:2011-02-19 12:08:47

标签: scala

是否可以在运行时获取scala变量的名称?

E.g。是否可以编写一个函数getIntVarName(variable: Int): String,其行为如下?

val myInt = 3
assert("myInt" === getIntVarName(myInt))

5 个答案:

答案 0 :(得分:12)

对于你需要做的事情,在我看来,运行时不是必需的,因为你已经在编译时定义了myInt变量。如果是这种情况,您只需要通过宏进行一些AST操作。

尝试

package com.natalinobusa.macros

import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context

object Macros {

  // write macros here
  def getName(x: Any): String = macro impl

  def impl(c: Context)(x: c.Tree): c.Tree = {
    import c.universe._
    val p = x match {
      case Select(_, TermName(s)) => s
      case _ => ""
    }
    q"$p"
  }
}

请注意,宏必须编译为单独的子项目,并且不能是必须应用宏替换的同一项目的一部分。检查此模板,了解如何定义此类宏子项目:https://github.com/echojc/scala-macro-template

scala> import Macros._
import Macros._

scala> val myInt = 3
myInt: Int = 3

scala> "myInt" == getName(myInt)
res6: Boolean = true

答案 1 :(得分:7)

基本上,它无法完成。

JVM不提供任何方法句柄(请记住,Scala属性被编码为字节码中的方法以支持统一访问原则)。你可以得到的最接近的是使用反射来查找在特定类上定义的方法列表 - 我感谢这对你的特殊需求没有帮助。

可以将其作为Scala功能实现,但它需要一个编译器插件从AST中获取相关的符号名称并将其作为字符串文字推送到代码中,所以不是我可以在一个简短的代码片段中演示:)

反射中经常出现的另一个命名问题是方法参数。那个至少我可以帮忙。我有一个work-in-progress reflection library here,它基于scalap使用的编译器生成的scala签名。它还没有准备好认真使用,但它正在积极发展。

答案 2 :(得分:3)

您可以使用scala-nameof获取变量名称,函数名称,类成员名称或类型名称。它发生在编译时,因此不涉及反射,也不需要运行时依赖。

val myInt = 3
assert("myInt" === nameOf(myInt))

将编译为:

val myInt = 3
assert("myInt" === "myInt")

答案 3 :(得分:2)

就像这样的元数据而言,Scala还没有比Java更多的东西。请关注Scala Reflection project,但我怀疑它会很快提供对局部变量的访问。在此期间,请考虑像ASM这样的字节码检查器库。另一个重要警告:编译期间局部变量名称丢失,因此您需要在“调试”模式下编译以保留它们。

答案 4 :(得分:1)

我认为不可能获得变量的名称,但您可以尝试使用对象:

object Test1 {
  def main(args: Array[String]) {
    object MyVar {
      def value = 1
    }
    println(MyVar.getClass)
  }
}

打印:class Test1$MyVar$2$。所以你可以从中获得'MyVar'。