How to access Case case field Value from string field name

How to extract the value of a field of the case class from a given String value representing this field.

For instance:

case class Person(name: String, age: Int) val a = Person("test",10) 

Now the string is given name or age . I want to extract a value from a variable. How can I do it? I know that this can be done using reflection, but I'm not quite sure how?

+5
source share
3 answers

What you are looking for can be achieved with Shapeless lenses. This will also limit the fact that the field actually exists in the case class at compile time, rather than at run time:

 import shapeless._ case class Person(name: String, age: Int) val nameLens = lens[Person] >> 'name val p = Person("myName", 25) nameLens.get(p) 

Productivity:

 res0: String = myName 

If you try to retrieve a non-existing field, you will get a compile-time error, which is a much more reliable guarantee:

 import shapeless._ case class Person(name: String, age: Int) val nonExistingLens = lens[Person] >> 'bla val p = Person("myName", 25) nonExistingLens.get(nonExistingLens) 

The compiler yells:

 Error:(5, 44) could not find implicit value for parameter mkLens: shapeless.MkFieldLens[Person,Symbol with shapeless.tag.Tagged[String("bla")]] val nonExistingLens = lens[Person] >> 'bla 
+6
source

I don’t know exactly what you had in mind, but the match operator could do this, it is not very general or extensible with respect to changes in the case Person class, but it meets your basic requirements without using reflection:

 scala> val a = Person("test",10) a: Person = Person(test,10) scala> def extract(p: Person, fieldName: String) = { | fieldName match { | case "name" => p.name | case "age" => p.age | } | } extract: (p: Person, fieldName: String)Any scala> extract(a, "name") res1: Any = test scala> extract(a, "age") res2: Any = 10 scala> extract(a, "name####") scala.MatchError: name#### (of class java.lang.String) at .extract(<console>:14) ... 32 elided 

UPDATE according to comment:

 scala> case class Person(name: String, age: Int) defined class Person scala> val a = Person("test",10) a: Person = Person(test,10) scala> def extract(p: Person, fieldName: String) = { | fieldName match { | case "name" => Some(p.name) | case "age" => Some(p.age) | case _ => None | } | } extract: (p: Person, fieldName: String)Option[Any] scala> extract(a, "name") res4: Option[Any] = Some(test) scala> extract(a, "age") res5: Option[Any] = Some(10) scala> extract(a, "name####") res6: Option[Any] = None scala> 
0
source

I think this can be done by converting the case class to Map, and then getting the field by name

 def ccToMap(cc: AnyRef) = (Map[String, Any]() /: cc.getClass.getDeclaredFields) { (a, f) => f.setAccessible(true) a + (f.getName -> f.get(cc)) } 

using

 case class Person(name: String, age: Int) val column = Person("me", 16) println(ccToMap(column)) val name = ccToMap(column)["name"] 
0
source

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


All Articles