4

私はScalaに不慣れで、暗黙の変換と有名なケーキパターンの可能性を探っています。実装の詳細が漏れないように、抽象型としてリストされたid値を持つモデルクラスを作成しようとしました。また、ケーキパターンの特性ラッパーに混ぜました。idからJSONへの暗黙の変換(Playフレームワーク内)を除いて、すべてが正常に機能します。Scalaコンパイラーは、私が何をしても暗黙の変換を見つけることができません。

問題を再現するコードは次のとおりです。

import anorm._
import play.api.libs.json._

trait Card {
  type Key
  val NoId: Key
  val id: Key
  val name: String
}

trait CardModelComponent {
  val cardModel: CardModel
  trait CardModel {
    def findById(id: Long): Option[Card]
    def findAll: Seq[Card]
    def delete(id: Long)
    def create(name: String): Option[Card]
  }
}

trait CardModelComponentImpl extends CardModelComponent {
  case class CardImpl(id: Pk[Long], name: String) extends Card {
    type Key = Pk[Long]

    object Key extends Writes[Key] {
      implicit def writes(key: Key): JsValue = {
        key match {
          case Id(idVal: Long) => JsNumber(idVal)
          case _ => JsNull
        }
      }
    }
    val NoId = NotAssigned
  }

  class CardModelImpl extends CardModel {
    def findById(id: Long): Option[Card] = { None }
    def findAll: Seq[Card] = { Seq(CardImpl(Id(1), "Some card"))}
    def delete(id: Long) {}
    def create(name: String): Option[Card] = { Some(CardImpl(Id(1), name)) }
  }
}

object ComponentsRegistry extends
CardModelComponentImpl {

  val cardModel = new CardModelImpl
}

val card = ComponentsRegistry.cardModel.create("Test card").get
Json.toJson(card.id)

私が得ているエラー出力は次のようなものです:

> card: Card = CardImpl(1,Test card)
> <console>:19: error: No Json deserializer found for type card.Key. Try to implem
  ent an implicit Writes or Format for this type.
                Json.toJson(card.id)
                           ^

それを機能させる方法はありますか?ケーキパターンのラッピングは、型名から推測できるように、コンパイラからあまりにも多くの型情報を隠しているように見えcard.Keyます。

また、PkのWriter実装を直接作成しようとしましたが、結果と同じエラーが発生しました。

4

3 に答える 3

2

メンバーメソッドではなく、暗黙的であるWrites[Key]べきインスタンスです。writes()暗黙的なインスタンスも、toJson()メソッドが呼び出されるスコープ内にある必要があります。

于 2013-01-14T10:22:11.440 に答える
1

私はあなたのコードを少し修正しました。これがお役に立てば幸いです。

package models
import anorm._
import play.api.libs.json._

trait Card[T] {
  val NoId: T
  val id: T
  val name: String
}

trait CardModelComponent[T] {
  val cardModel: CardModel
  trait CardModel {
    def findById(id: Long): Option[Card[T]]
    def findAll: Seq[Card[T]]
    def delete(id: Long)
    def create(name: String): Option[Card[T]]
  }
}

trait CardModelComponentImpl extends CardModelComponent[Pk[Long]] {
  type Key = Pk[Long]
  case class CardImpl(id: Key, name: String) extends Card[Key] {
    val NoId = NotAssigned
  }


  class CardModelImpl extends CardModel {
    def findById(id: Long): Option[Card[Key]] = { None }
    def findAll: Seq[Card[Key]] = { Seq(CardImpl(Id(1), "Some card"))}
    def delete(id: Long) {}
    def create(name: String): Option[Card[Key]] = { Some(CardImpl(Id(1), name)) }
  }
}

object ComponentsRegistry extends CardModelComponentImpl {
  val cardModel = new CardModelImpl
  implicit object KeyWrites extends Writes[Key] {
    def writes(key: Key): JsValue = {
      key match {
        case Id(idVal: Long) => JsNumber(idVal)
        case _ => JsNull
      }
    }
  }
}

そして、次のように使用できます。

import models.ComponentsRegistry
import models.ComponentsRegistry.KeyWrites
val card = ComponentsRegistry.cardModel.create("Test card").get
Json.toJson(card.id)
于 2013-01-14T10:58:00.037 に答える
1

Jesper Nordenberg が書いたように、Writes[Key] のインスタンスをスコープに入れる必要があります。これを行う 1 つの方法は、次のように、Card の実装が Writer インスタンスを発行し、それを toJson を呼び出す場所にインポートすることを要求することです。

...

trait Card {
  type Key

  val NoId: Key
  val id: Key
  val name: String
  implicit val Key: Writes[Key]
}

...

trait CardModelComponentImpl extends CardModelComponent {
  case class CardImpl(id: Pk[Long], name: String) extends Card {
    type Key = Pk[Long]

    implicit object Key extends Writes[Key] {
      def writes(key: Key): JsValue = {
        key match {
          case Id(idVal: Long) => JsNumber(idVal)
          case _ => JsNull
        }
      }
    }

    val NoId = NotAssigned
  }

  class CardModelImpl extends CardModel {
    def findById(id: Long): Option[Card] = { None }
    def findAll: Seq[Card] = { Seq(CardImpl(Id(1), "Some card"))}
    def delete(id: Long) {}
    def create(name: String): Option[Card] = { Some(CardImpl(Id(1), name)) }
  }
}

...

val card = ComponentsRegistry.cardModel.create("Test card").get
import card.Key
Json.toJson(card.id)

または明示的に渡します:

val card = ComponentsRegistry.cardModel.create("Test card").get
Json.toJson(card.id)(card.Key)
于 2013-01-14T10:43:43.370 に答える