Get Scala variable name at runtime

后端 未结 5 1271
甜味超标
甜味超标 2020-12-16 17:03

Is it possible to get the name of a scala variable at runtime?

E.g. is it possible to write a function getIntVarName(variable: Int): String behaving as

相关标签:
5条回答
  • 2020-12-16 17:44

    You can use scala-nameof to get a variable name, function name, class member name, or type name. It happens at compile-time so there's no reflection involved and no runtime dependency needed.

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

    will compile to:

    val myInt = 3
    assert("myInt" === "myInt")
    
    0 讨论(0)
  • 2020-12-16 17:45

    Basically, it can't be done.

    The JVM offers nothing by way of a Method handle (remember, Scala properties are encoded as methods in bytecode to support the uniform access principle). The closest you can get is to use reflection to find a list of methods defined on a particular class - which I appreciate doesn't help with your particular need.

    It is possible to implement this as a Scala feature, but it would require a compiler plugin to grab the relevant symbol name from the AST and push it into code as a string literal, so not something I could demonstrate in a short code snippet :)

    The other naming problem that often comes up in reflection is method parameters. That one at least I can help with. I have a work-in-progress reflection library here that's based on the compiler-generated scala signature as used by scalap. It's nowhere near being ready for serious use, but it is under active development.

    0 讨论(0)
  • 2020-12-16 17:47

    For what you need to do, It seems to me that runtime is not required, since you already have your myInt variable defined at compile time. If this is the case, you just need a bit of AST manipulation via a macro.

    Try

    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"
      }
    }
    

    Be aware that macro's must be compiled as a separate subproject, and cannot be part of the same project where the macro substitution has to be applied. Check this template on how to define such a macro sub-project: 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
    
    0 讨论(0)
  • 2020-12-16 17:54

    Scala doesn't yet have much more than Java in terms of metadata like this. Keep an eye on the Scala Reflection project, but I doubt that will offer access to local variables anytime soon. In the meantime, consider a bytecode inspector library like ASM. Another big caveat: local variable names are lost during compilation, so you'd need to compile in "debug" mode to preserve them.

    0 讨论(0)
  • 2020-12-16 17:54

    I don't think it's possible to get the name of a variable, but you can try it with objects:

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

    This prints: class Test1$MyVar$2$. So you can get 'MyVar' out of it.

    0 讨论(0)
提交回复
热议问题