在返回对象实例时获得“不兼容的类型”

时间:2013-04-26 06:48:20

标签: mongodb scala playframework-2.0

我正在写一个游戏! 2.1使用ReactiveMongo的应用程序。每个可持久化的case类都有一个对象,它包含2个隐式对象,实现BSONReader [...]和BSONWriter [...],每个case类都有返回这些的方法:

  trait Persistable {
    implicit def getReader: BSONReader[Persistable]
    implicit def getWriter: BSONWriter[Persistable]
    val collectionName: String
  }

  case class MyObj () extends Persistable {
    override val collectionName: String = MyObj.collectionName
    override def getReader: BSONReader[MyObj] = MyObj.MyObjBSONReader
    override def getWriter: BSONWriter[MyObj] = MyObj.MyObjBSONWriter
  }

  object MyObj{
    val collectionName: String = "MyObj"

    implicit object MyObjBSONReader extends BSONReader[MyObj] {
      def fromBSON(document: BSONDocument): MyObj = {
        val doc = document.toTraversable
        new MyObj(
        )
      }
    }

    implicit object MyObjBSONWriter extends BSONWriter[MyObj] {
      def toBSON(myObj: MyObj) = {
        BSONDocument(
        )
      }
    }

出于某种原因,getReader似乎工作正常,但getWriter错误:

  

在trait中覆盖方法getWriter可以继承type =   reactivemongo.bson.handlers.BSONWriter [models.persistable.Persistable];   方法getWriter具有不兼容的类型

我在做错了什么?两者似乎都有类似的签名。 另一个提示是,如果我从getWriter中删除返回类型,我在eclipse中得到complie time error:

  

类型不匹配;发现:models.persistable.MyObj.MyObjBSONWriter.type required:   reactivemongo.bson.handlers.BSONWriter [models.persistable.Persistable]

更新

我做了@AndrzejDoyle,如下所述,但随后执行Persister,这是本次练习的核心,抱怨道:

def insert(persistable: Persistable) = {
    val collection = db(persistable.collectionName)
    import play.api.libs.concurrent.Execution.Implicits._

    implicit val reader = persistable.getReader
    implicit val writer = persistable.getWriter
    collection.insert(persistable)
}

错误:

  

特质持久性类型        参数

1 个答案:

答案 0 :(得分:1)

这是由于协方差和逆转。

mongodb阅读器定义为BSONReader[+DocumentType]。泛型参数中的+表示该类在该参数中是协变。或者更全面,

  

如果BA的子类,则BSONReader[B]BSONReader[A]的子类。

因此,您可以在需要BSONReader[MyObj]的任何地方使用BSONReader[Persistable]

另一方面,作者是逆变BSONWriter[-DocumentType]。这意味着

  

如果BA的子类,则BSONWriter[B]BSONWriter[A]超类

因此,BSONWriter[MyObj] BSONWriter[Persistable]的子类,因此无法在其位置使用。


这最初可能看起来令人困惑(即“为什么逆转是有意义的,当'倒退'时?”)。但是,如果你考虑类正在做什么,它会变得更加清晰。读者可能会生成其泛型参数的一些实例。然后调用者可能会期望它生成Persistable - 如果您有一个专门生成MyObj的版本,那么这很好。

另一方面,作者可能给出其泛型参数的对象。具有BSONWriter[Persistable]的呼叫者将调用write()方法,并传入要写入的Persistable实例。您的实现可以编写MyObj的实例,因此它实际上与接口不匹配。另一方面,BSONWriter[Object]将是任何BSONWriter的子类,因为它可以(从类型的角度来看)接受任何类型作为参数。


根本问题似乎是你的Persistable特征比你想要的更宽松。您可能希望每个实现都返回在本身上参数化的读取器和写入器,而不是通常在Persistable上。您可以通过self-bounded generics

实现此目的
trait Persistable[T <: Persistable[T]] {
    implicit def getReader: BSONReader[T]
    implicit def getWriter: BSONWriter[T]
    val collectionName: String
}

然后将该类声明为MyObj[MyObj]。现在,读者和作者应该在MyObj上进行参数化,并且现有的实现将被编译。