【问题标题】:Extract case class field name in Scala在Scala中提取案例类字段名称
【发布时间】:2016-04-20 01:31:40
【问题描述】:

我有一个案例类:

case class A(field1: String, field2: Int)

我想在某些代码中引用确切的字符串“field1”,例如:

val q = Query("field1"-> "hello")
performQuery(q)

现在我必须小心我始终正确输入“field1”。为避免这种情况,我想使用对A.field1 的引用作为字符串,如下所示:

val q = Query(A.field1 -> "hello")
performQuery(q)

这将帮助我避免任何输入错误,而且如果我稍后重命名这些字段,我不需要更新其余的代码库字符串。我可以依靠 IDE。

如何将案例类字段名称提取为字符串?

EDIT1

这是用法的另一种变体:

// capture the field name
val FIELD1_NAME = A.field1 // this implementation can change

此时FIELD1_NAME 应该包含"field1" 作为字符串

// Now use the string obtained above to create a query:
val q = Query(FIELD1_NAME -> "hello")
performQuery(q)

【问题讨论】:

  • 它看起来不太好,因为A 本身是您的上下文中没有此字段field1 的伴随对象,即使它有它也会评估此字段的内容。我猜如果可能的话,你需要宏。
  • @Łukasz 我也想到了宏。但是,我没有足够的宏专业知识来继续前进。什么是实现我所描述的好方法?
  • 问题是我也没有 :D 我们需要等待。
  • 好吧,宏在扩展之前仍然需要进行类型检查,A.field1 不会。 Query[A](_.field1 -> "hello")呢?
  • @AlexeyRomanov 我更新了问题以澄清它不限于A.field1 以任何方式。我们可以使用任何方法,只要我们可以在 Scala 代码中提取 field1。

标签: scala


【解决方案1】:

发现于https://gist.github.com/dwickern/b47606a1ed2319afa6e2:

import scala.annotation.tailrec
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

object Macros {
  def nameOfImpl(c: blackbox.Context)(x: c.Tree): c.Tree = {
    import c.universe._

    @tailrec def extract(x: c.Tree): String = x match {
      case Ident(TermName(s)) => s
      case Select(_, TermName(s)) => s
      case Function(_, body) => extract(body)
      case Block(_, expr) => extract(expr)
      case Apply(func, _) => extract(func)
    }

    val name = extract(x)
    q"$name"
  }
  def nameOfMemberImpl(c: blackbox.Context)(f: c.Tree): c.Tree = nameOfImpl(c)(f)

  def nameOf(x: Any): String = macro nameOfImpl
  def nameOf[T](f: T => Any): String = macro nameOfMemberImpl
}

//
// Sample usage:
//

val someVariable = ""
Macros.nameOf(someVariable) // "someVariable"

def someFunction(x: Int): String = ???
Macros.nameOf(someFunction _) // "someFunction"

case class SomeClass(someParam: String)
val myClass = SomeClass("")
Macros.nameOf(myClass.someParam) // "someParam"

// without having an instance of the class:
Macros.nameOf[SomeClass](_.someParam) // "someParam"

对于您的用例,Query(nameOf[A](_.field1) -> "hello")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-24
    • 2013-04-11
    • 2021-01-27
    • 2014-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多