Scala getting field and field type of class case

So, I'm trying to get the field and their types in the case class. At the moment I'm doing it like this

typeOf[CaseClass].members.filter(!_.isMethod).foreach{ x => x.typeSignature match { case _:TypeOfFieldInCaseClass => do something case _:AnotherTypeOfFieldInCaseClass => do something } } 

problem x.typeSignature is of type reflect.runtime.universe.Type , which cannot match any of the types that are in the case class. Is there any way to do this?

+6
source share
1 answer

Suppose you define the following class:

 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 is the first attempt not working?

This is because you use type templates in your code. Sample templates check the subjectโ€™s type for consistency โ€” which is the type signature in this case โ€” at runtime. Thus, using _: Int , we request a type check at runtime against each type signature of the non-method CaseClass .

But in this case, we need a match of values.

Let's consider in more detail (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, we want to combine the 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!

Therefore, we need to match them with different values โ€‹โ€‹of this type, which we can easily get with typeOf[Int] and typeOf[String] .

A bit more about pattern matching in Scala

You can make the code shorter 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 will give you the following compilation error:

 not found: type typeOf 

Again, this is because here you need to map the variable name starting 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 information on pattern matching, see Programming in Scala . You will find a detailed explanation of pattern matching.

+9
source

Source: https://habr.com/ru/post/977058/


All Articles