How To Access access Case class field Value from String name of the field

前端 未结 3 2027
忘掉有多难
忘掉有多难 2021-01-04 19:51

How should I extract the value of a field of a case class from a given String value representing the field.

For example:

case class Person(name: Stri         


        
相关标签:
3条回答
  • 2021-01-04 20:27

    I think it can do by convert case class to Map, then get field by name

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

    Usage

    case class Person(name: String, age: Int)
    
    val column = Person("me", 16)
    println(ccToMap(column))
    val name = ccToMap(column)["name"]
    
    0 讨论(0)
  • 2021-01-04 20:30

    don't know exactly what you had in mind, but a match statement would do, it is not very generic or extensible with regards changes to the Person case class, but it does meet your basic requirements of not 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 as per 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 讨论(0)
  • 2021-01-04 20:41

    What you're looking for can be achieve using Shapeless lenses. This will also put the constraint that a field actually exists on a case class at compile time rather than run time:

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

    Yields:

    res0: String = myName
    

    If you try to extract a non existing field, you get a compile time error, which is a much stronger guarantee:

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

    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
    
    0 讨论(0)
提交回复
热议问题