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?
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")
}
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]
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With