Scala Reflection to update a case class val

后端 未结 2 1685
不知归路
不知归路 2021-01-13 16:45

I\'m using scala and slick here, and I have a baserepository which is responsible for doing the basic crud of my classes. For a design decision, we do have updatedTime and c

2条回答
  •  一向
    一向 (楼主)
    2021-01-13 17:09

    As comments have said, don't change a val using reflection. Would you that with a java final variable? It makes your code do really unexpected things. If you need to change the value of a val, don't use a val, use a var.

    trait HasCreatedAt {
        var createdAt: Option[DateTime] = None
    }
    
    case class User(name:String) extends HasCreatedAt
    

    Although having a var in a case class may bring some unexpected behavior e.g. copy would not work as expected. This may lead to preferring not using a case class for this.

    Another approach would be to make the insert method return an updated copy of the case class, e.g.:

    trait HasCreatedAt {
        val createdAt: Option[DateTime]
        def withCreatedAt(dt:DateTime):this.type
    }
    
    case class User(name:String,createdAt:Option[DateTime] = None) extends HasCreatedAt {
        def withCreatedAt(dt:DateTime) = this.copy(createdAt = Some(dt))
    }
    
    trait BaseRepo[ID, R <: HasCreatedAt] {
        def insert(r: R)(implicit session: Session): (ID, R) = {
            val id = ???//insert into db
            (id, r.withCreatedAt(??? /*now*/))
        }
    }
    

    EDIT:

    Since I didn't answer your original question and you may know what you are doing I am adding a way to do this.

    import scala.reflect.runtime.universe._
    
    val user = User("aaa", None)
    val m = runtimeMirror(getClass.getClassLoader)
    val im = m.reflect(user)
    val decl = im.symbol.asType.toType.declaration("createdAt":TermName).asTerm
    val fm = im.reflectField(decl)
    fm.set(??? /*now*/)
    

    But again, please don't do this. Read this stackoveflow answer to get some insight into what it can cause (vals map to final fields).

提交回复
热议问题