在运行时获取 Scala 变量名称

发布于 2024-10-18 10:34:59 字数 191 浏览 3 评论 0原文

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

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

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

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 follows?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

剪不断理还乱 2024-10-25 10:34:59

对于您需要做的事情,在我看来,不需要运行时,因为您已经在编译时定义了 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-宏模板

scala> import Macros._
import Macros._

scala> val myInt = 3
myInt: Int = 3

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

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
乱了心跳 2024-10-25 10:34:59

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

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

将编译为:

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

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")
小耗子 2024-10-25 10:34:59

基本上是做不到的。

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

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

反射中经常出现的另一个命名问题是方法参数。至少这一点我可以帮忙。我这里有一个正在进行中的反射库,它基于编译器生成的 scala 签名,如下所示由scalap使用。它还远未准备好投入实际使用,但正在积极开发中。

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.

暮凉 2024-10-25 10:34:59

在这样的元数据方面,Scala 还没有比 Java 更多的东西。密切关注 Scala Reflection 项目,但我怀疑它会很快提供对局部变量的访问。同时,请考虑使用字节码检查器库,例如 ASM。另一个重要的警告:局部变量名称在编译过程中会丢失,因此您需要在“调试”模式下编译以保留它们。

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.

ま昔日黯然 2024-10-25 10:34:59

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

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

此打印:class Test1$MyVar$2$。这样你就可以从中得到“MyVar”。

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.

关于从前 2024-10-25 10:34:59

这可以通过 Scala 3 宏来实现(在编译时完成)。

创建一个宏对象(必须位于单独的文件中):

import scala.quoted.{Expr, Quotes}

object NameFromVariable :

  def inspectCode(x: Expr[Any])(using Quotes): Expr[String] =
    val name = x.show.split("""\.""").last
    Expr(name)

然后您的类中需要一个内联方法。

inline def getIntVarName(inline x: Any): Any = ${ NameFromVariable.inspectCode('x) }

并使用这种方法,例如:

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

参见官方文档: https:// docs.scala-lang.org/scala3/guides/macros/macros.html

This can be achieved with Scala 3 Macros (does it at compile time).

Create a Macro object (this must be in a separate file):

import scala.quoted.{Expr, Quotes}

object NameFromVariable :

  def inspectCode(x: Expr[Any])(using Quotes): Expr[String] =
    val name = x.show.split("""\.""").last
    Expr(name)

Then you need an inline method in your class.

inline def getIntVarName(inline x: Any): Any = ${ NameFromVariable.inspectCode('x) }

And use this method, like:

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

See the official documentation: https://docs.scala-lang.org/scala3/guides/macros/macros.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文