【发布时间】:2017-08-17 17:28:02
【问题描述】:
所以,假设我有一个带有逆变类型参数的类:
trait Storage[-T] {
def list(path: String): Seq[String]
def getObject[R <: T](path: String): Future[R]
}
类型参数的想法是将实现限制在它可以返回的类型的上限。所以,Storage[Any] 可以读取任何内容,而Storage[avro.SpecificRecord] 可以读取 avro 记录,但不能读取其他类:
def storage: Storage[avro.SpecificRecord]
storage.getObject[MyAvroDoc]("foo") // works
storage.getObject[String]("bar") // fails
现在,我有一个实用程序类,可用于遍历给定位置的对象:
class StorageIterator[+T](
val storage: Storage[_ >: T],
location: String
)(filter: String => Boolean) extends AbstractIterator[Future[T]] {
val it = storage.list(location).filter(filter)
def hasNext = it.hasNext
def next = storage.getObject[T](it.next)
}
这可行,但有时我需要从下游迭代器访问底层storage,以从辅助位置读取另一种类型的对象:
def storage: Storage[avro.SpecificRecord]
val iter = new StorageIterator[MyAvroDoc]("foo")
iter.storage.getObject[AuxAvroDoc](aux)
这当然行不通,因为storage类型参数是通配符,没有证据证明可以用来读取AuxAvroDoc
我尝试这样修复它:
class StorageIterator2[P, +T <: P](storage: Storage[P])
extends StorageIterator[T](storage)
这可行,但现在我必须在创建它时指定两个类型参数,这很糟糕:(
我试图通过向Storage 本身添加一个方法来解决它:
trait Storage[-T] {
...
def iterate[R <: T](path: String) =
new StorageIterator2[T, R](this, path)
}
但这不会编译,因为它将T 置于一个不变的位置:(
如果我使P 逆变,那么StorageIterator2[-P, +T <: P] 失败,因为它认为P occurs in covariant position in type P of value T。
最后一个错误我不明白。为什么 P 在这里不能逆变?如果这个位置真的是协变的(为什么会这样?)那么为什么它允许我在那里指定一个不变的参数呢?
最后,有人知道我该如何解决这个问题吗? 基本上,这个想法是能够
- 做
storage.iterate[MyAvroDoc]而不必再次给它上边界,并且 - 执行
iterator.storage.getObject[AnotherAvroDoc]无需强制转换存储以证明它可以读取此类对象。
感谢任何想法。
【问题讨论】: