Scala traits using generics and case class methods

て烟熏妆下的殇ゞ 提交于 2019-12-06 09:18:29

If there some easy solution here, can a generic be declared as needing to be a type of case?

No.

Or should the Model trait declare a copy method that any extending class has to implement and by being a case class it does so?

Unfortunately, also no. An abstract copy method won't work for two reasons.

First, if you declare an abstract copy method in your trait, it will actually prevent the case class that extends it from automatically generating it, and you're forced to implement it yourself.

Second, it's hard to require such a generic method such as that. What I mean is, when you declare an abstract method, you need to specify the full signature. However, one would assume that all case classes that extend Model will not have the same signatures, so they cannot have the same copy method. It just can't work that way.

Unfortunately that leaves you with needing to implement similar methods yourself for sub-classes. I do this sort of thing filling ids using F-bounded polymorphism:

trait Model[M <: Model[M]] { this: M =>
    def id: Option[Long]
    def withId(id: Long): M
}

case class MyModel(id: Option[Long], ...) extends Model[MyModel] {
    def withId(id: Long): MyModel = this.copy(id = Some(id))
}

trait DAO[M <: Model[M]] {
   def insert(model: M): M = {
     ... do work
     m.withId(someGeneratedId)
   }
}

The bit of repeated code is ugly, but enough to live with. Perhaps it may be possible to do something like this with reflection or a macro, but that would likely be anything but simple.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!