我想编写如下函数:
def printFieldOfClass(field: ???) =
println(field)
假设有一个案例类定义,例如case class A(id: String)
。然后可以调用printFieldOfClass(A.id)
来打印字符串"A.id"
。但是,如果我们尝试调用printFieldOfClass(A.idd)
,我希望代码不要编译。这甚至可能吗?如果是这样,参数的类型是什么field
?
非常感谢帮助!
编辑:由于对我要做的事情似乎有些困惑,让我澄清一下:我不想传递案例类的实例 ,我更愿意在类定义中传递对某些字段的引用。此外,我不希望我的函数硬连线到任何这样的类,它应该适用于所有Scala类,如下所示:printFieldOfClass(SomeClassTheFunctionDoesNotKnowAbout.someField)
应该打"SomeClassTheFunctionDoesNotKnowAbout.someField"
以防SomeClassTheFunctionDoesNotKnowAbout
&#39 ; s定义指定字段someField
,或者,如果类没有这样的字段,则调用不应该编译。
答案 0 :(得分:2)
如果printFieldOfClass
是正常方法,这是不可能的,正如评论所解释的那样。但你可以把它变成一个宏。它基本上是一个在编译时运行的函数,接收其参数的语法树并生成一个新树来替换它。 Scala宏有很多介绍,在答案中写另一个没有意义。但是我不建议尝试它,直到你对Scala一般都很满意。
An example做了一些接近你想要的事情:
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"