Scala类的字段类型是什么?
我想编写如下函数:Scala类的字段类型是什么?,scala,Scala,我想编写如下函数: def printFieldOfClass(field: ???) = println(field) 假设有一个case类定义,例如case class a(id:String)。然后可以调用类(A.id)的printfield,它将打印字符串“A.id”。但是,如果我们尝试调用printFieldOfClass(A.idd),我希望代码不要编译。这可能吗?如果是,参数字段的类型是什么 非常感谢您的帮助 编辑:由于我试图做的事情似乎有些混乱,让我澄清一下:我不想传递ca
def printFieldOfClass(field: ???) =
println(field)
假设有一个case类定义,例如case class a(id:String)
。然后可以调用类(A.id)的printfield
,它将打印字符串“A.id”
。但是,如果我们尝试调用printFieldOfClass(A.idd)
,我希望代码不要编译。这可能吗?如果是,参数字段的类型是什么
非常感谢您的帮助
编辑:由于我试图做的事情似乎有些混乱,让我澄清一下:我不想传递case类的实例,我更希望传递对类定义中某个字段的引用。另外,我不希望我的函数硬连接到任何这样的类,它应该与所有Scala类一起工作,比如:printFieldOfClass(someClasstheFunctionsNotKnowAbout.someField)
应该打印“someClasstheFunctionsNotKnowAbout.someField”
如果someclasses函数不知道
的定义指定了一个字段someField
,或者,如果类没有这样的字段,调用就不应该编译。如果类的printfield
是一个普通方法,这是不可能的,正如注释所解释的。但您可以将其改为宏。它基本上是一个在编译时运行的函数,接收其参数的语法树并生成一个新的树来替换它。关于Scala宏有很多介绍,在答案中再写一个是没有意义的。但我不建议你尝试它,直到你对Scala总体上很满意为止
它的功能与您想要的非常接近:
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"
如果printFieldOfClass
是一个正常的方法,这是不可能的,正如注释所解释的。但您可以将其改为宏。它基本上是一个在编译时运行的函数,接收其参数的语法树并生成一个新的树来替换它。关于Scala宏有很多介绍,在答案中再写一个是没有意义的。但我不建议你尝试它,直到你对Scala总体上很满意为止
它的功能与您想要的非常接近:
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"
如果该字段不存在,当然不会编译。如果字段存在,则函数无法知道作为参数获取的值来自何处。最后,这样做似乎毫无意义。顺便说一句,如果A
不是一个单例,A.field
将永远不会编译,即使类A
上有一个fieldfield
,我也不明白。函数是否需要知道作为参数获取的值来自何处?你说“来自”是什么意思?想想看。该方法接收任何类型的值。它怎么可能追溯到某个类的某个字段?没有办法做到这一点,而能够做到这一点是没有意义的it@Dici在几乎所有的语言中,你都是正确的。但是Scala宏允许你这样做。如果这个字段不存在,当然它不会编译。如果字段存在,则函数无法知道作为参数获取的值来自何处。最后,这样做似乎毫无意义。顺便说一句,如果A
不是一个单例,A.field
将永远不会编译,即使类A
上有一个fieldfield
,我也不明白。函数是否需要知道作为参数获取的值来自何处?你说“来自”是什么意思?想想看。该方法接收任何类型的值。它怎么可能追溯到某个类的某个字段?没有办法做到这一点,而能够做到这一点是没有意义的it@Dici在几乎所有的语言中,你都是正确的。但是Scala宏允许您这样做。什么是q
?在这里找不到@JensHoffmann哦,我明白了,当然。它必须返回一个语法树,因此这用于转换。谢谢,难道不能有一个nameOfImpl
方法吗?您的两个方法具有相同的实现和签名。什么是q
?在这里找不到@JensHoffmann哦,我明白了,当然。它必须返回一个语法树,因此这用于转换。谢谢,难道不能有一个nameOfImpl
方法吗?两个方法具有相同的实现和签名。