我正在写一个游戏! 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错误:
我在做错了什么?两者似乎都有类似的签名。 另一个提示是,如果我从getWriter中删除返回类型,我在eclipse中得到complie time error:在trait中覆盖方法getWriter可以继承type = reactivemongo.bson.handlers.BSONWriter [models.persistable.Persistable]; 方法getWriter具有不兼容的类型
类型不匹配;发现: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)
}
错误:
特质持久性类型 参数
答案 0 :(得分:1)
这是由于协方差和逆转。
mongodb阅读器定义为BSONReader[+DocumentType]
。泛型参数中的+表示该类在该参数中是协变。或者更全面,
如果
B
是A
的子类,则BSONReader[B]
是BSONReader[A]
的子类。
因此,您可以在需要BSONReader[MyObj]
的任何地方使用BSONReader[Persistable]
。
另一方面,作者是逆变:BSONWriter[-DocumentType]
。这意味着
如果
B
是A
的子类,则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
上进行参数化,并且现有的实现将被编译。