4

現在、次のように見えるいくつかのモデルをリファクタリングしようとしています。

case class Person(name: String, age: Int)

object Person {
    implicit val reads: Reads[Person] = (
        (JsPath \ "name").read[String] and
        (JsPath \ "age").read[Int] 
    )(Person.apply _)
}

このようなものに:

abstract class BaseModel {
    val pk: String  // Some stuff here that will be common
}

object BaseModel {
    implicit val reads: Reads[BaseModel] // Not sure what to do here
}

私がこれを行うことができるように:

trait MyTrait[Model <: BaseModel] {

    // More code here
    val body: JsObject = ...
    val parsed = body.validate[Model]  // Error: There is no implicit value defined for Model

}


case class NewPerson extends BaseModel {...}
object NewPerson {...} // Maybe need to extend something here


class MyController extends MyTrait[NewPerson]

すべてのモデルで暗黙的な読み取り値を定義する必要がありますが、抽象クラスのコンパニオン オブジェクトでこれを示す方法がわかりません。

4

1 に答える 1

6

抽象クラス/コンパニオンのペアを一緒に拡張することを強制する言語機能はありません。抽象クラスの「コンパニオン」をトレイトにすることで、このミッシングリンクを克服しました。このようなもの:

abstract class BaseModel {
     val pk: String
}

trait ModelCompanion[A <: BaseModel] { self: Singleton =>
    implicit val reads: Reads[A]
}

case class Person(name: String, age: Int) extends BaseModel

object Person extends BaseModel[Person] {
    ...
}

残念ながら、これはまだMyTrait(OP で定義されているように) aModel <: BaseModelが暗黙的Reads[Model]なものを見つけることができるコンパニオンを持っていることを示していません。MyTraitここでも、モデルのコンパニオン オブジェクトへの参照を保持する必要があるため、手動でリンクを作成する必要があります。

trait MyTrait[Model <: BaseModel] {

    def companion: ModelCompanion[Model]

    implicit def reads: Reads[Model] = companion.reads

    // More code here
    val body: JsObject = ...
    val parsed = body.validate[Model]  // Now this would work

}

object MyTraitImpl extends MyTrait[Person] {
    def companion = Person
}
于 2016-04-18T03:33:06.050 に答える