问题
So I'm trying to get the field and their types in a case class. At the moment I am doing it like so
typeOf[CaseClass].members.filter(!_.isMethod).foreach{
x =>
x.typeSignature match {
case _:TypeOfFieldInCaseClass => do something
case _:AnotherTypeOfFieldInCaseClass => do something
}
}
the problem is x.typeSignature is of type reflect.runtime.universe.Type which cannot match on any of the types that reside in the case class. Is there some way to do this?
回答1:
Let's say you have the following case class defined:
case class CaseClass(i: Int, s: String)
with pattern matching you can achieve what you want with the following:
import scala.reflect.runtime.universe._
typeOf[CaseClass].members.filter(!_.isMethod).map(_.typeSignature).foreach {
case t if t == typeOf[Int] => print("i")
case s if s == typeOf[String] => print("s")
}
Why?
So why the first attempt does not work?
That's because in your code you are using type-patterns. Type patterns check the type of subject-to-match - which is a type signature in this case - at runtime. So by using _: Int we are asking for a type check at runtime against each type signature of non-method members of CaseClass.
But in this case what we need is a value match.
Let's take a closer look (using Scala REPL):
scala> case class CaseClass(i: Int, s: String)
defined class CaseClass
scala> typeOf[CaseClass]
res1: reflect.runtime.universe.Type = CaseClass
scala> typeOf[CaseClass].members
res2: reflect.runtime.universe.MemberScope = Scopes(method equals, method toString, ..)
scala> typeOf[CaseClass].members.filter(!_.isMethod)
res4: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(value s, value i)
scala> typeOf[CaseClass].members.filter(!_.isMethod).map(_.typeSignature)
res5: Iterable[reflect.runtime.universe.Type] = List(String, scala.Int)
So what we want to match is of type reflect.runtime.universe.Type. Note that in the last line, String and scala.Int are just string representations of these types not their actual type!
So we need to match them against different values of this type which we can easily get with typeOf[Int] and typeOf[String].
A bit more on pattern matching in Scala
You may want to make the code more concise by using the following code:
typeOf[CaseClass].members.withFilter(!_.isMethod).map(_.typeSignature).foreach {
case typeOf[Int] => print("i") // Won't Compile!
case typeOf[Int] => print("s") // Won't Compile
}
But this give you the following compile error:
not found: type typeOf
Again this is because here we need to match against a variable name beginning with an uppercase letter. So the following works:
val T = typeOf[Int]
val S = typeOf[String]
typeOf[CaseClass].members.withFilter(!_.isMethod).map(_.typeSignature).foreach {
case T => print("i")
case S => print("s")
}
For more details on pattern matching, refer to Programming in Scala. You will find a detailed explanation of pattern matching there.
来源:https://stackoverflow.com/questions/26500539/scala-getting-field-and-type-of-field-of-a-case-class