所以,讓我們說我有一個類與逆變類型參數:故障類型差異
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]
無需進行轉換存儲,以證明它可以讀取該類型的對象。
任何想法表示讚賞。
「的存儲[T ]是你給路徑的對象,並且會輸出Ts。「這不是真的。 'T'不是'Storage'返回的對象的類型,而是它可能返回的所有_all_對象的共同超類型(當然,它們都是Ts,但這是一個技術性問題,而不是概念性特徵)。 它需要是不相容的,因爲'Storage [Any]'可以像'Stroage [Foo]'一樣使用。 – Dima
「你說這應該是相反的,Storage [T]應該知道如何輸出T的任何子類型,但是如何工作?」 我在問題中展示了一個例子。例如,如果'T'是avro structs的基類,那麼'Storage'可以讀取任何avro doc。它可以是'ThriftStruct'來讀取thrift,或者''Message'用於protobuf,'Product'用於csv等等。對於應用程序中的每個avro doc都有一個單獨的'Storage'類是沒有意義的,這就是如果它是協變的,將會發生什麼。 – Dima
Casting和'match''ing可能是一個解決方法,但這是一種java方式來做事情。避免這種類型的黑客正是首先出現類型差異的目的。這個想法是能夠在編譯時聲明:「該對象可以讀取任何avro文檔而不是其他任何東西」,而不會在運行時產生錯誤,當它運行到不應該的東西時。 – Dima