考慮下面的兩個代碼。他們完成相同的目標:只有這樣A[T]
-s可以存儲在T
延伸C
斯卡拉存在與協方差
但是他們使用兩種不同的方法來實現這一目標的Container
:
1)existentials
2)協方差
我更喜歡第一種解決方案,因爲A
保持簡單。爲什麼我會想要使用第二種解決方案(協方差),有什麼理由嗎?
我與第二個解決方案的問題是,它是在這個意義上,它不應該是A
-s責任來形容我可以在一個容器倉庫並沒有什麼不自然,這應該是容器的責任。第二種解決方案也是更復雜一旦我想開始在A
上運行,然後我必須處理所有與協變有關的東西。
使用第二種(更復雜,不太自然)的解決方案會帶來什麼好處?
object Existentials extends App {
class A[T](var t:T)
class C
class C1 extends C
class C2 extends C
class Z
class Container[T]{
var t:T = _
}
val c=new Container[A[_<:C]]()
c.t=new A(new C)
// c.t=new Z // not compile
val r: A[_ <: C] = c.t
println(r)
}
object Cov extends App{
class A[+T](val t:T)
class C
class C1 extends C
class C2 extends C
class Z
class Container[T]{
var t:T = _
}
val c: Container[A[C]] =new Container[A[C]]()
c.t=new A(new C)
//c.t=new A(new Z) // not compile
val r: A[C] = c.t
println(r)
}
EDIT(響應阿列克謝的答案):
評論: 「我與第二個解決方案的問題是,它不是在某種意義上說,它不應該是作爲責任自然描述我可以在集裝箱中儲存什麼,哪些不是,這應該是集裝箱的責任。「
如果非要class A[T](var t:T)
這意味着,我可以僅存儲A[T]
在容器-s和不(A[S]
其中S<:T
),在任何容器。
但是,如果我有class A[+T](var t:T)
那麼我可以存儲A[S]
哪裏S<:T
以及任何容器。
因此,當聲明A
或者是不變的或協變時,我決定哪種類型的A [S]可以存儲在一個容器中(如上所示),這個決定發生在聲明A
。
不過,我認爲,這個決定應該發生,相反,在容器的聲明,因爲它是具體的東西將被允許進入該容器中,只有A[T]
-s或也A[S]
其中S<:T
-s容器。
換句話說,改變A[T]
方差具有全球影響,同時改變一個容器的類型參數從A[T]
到A[_<:S]
已經容器本身上的良好限定的局部作用。所以「變化應該有局部效應」的原則也有利於生存解決方案。
感謝您的回答。 「另外,如果你忘記在一種方法中使用正確的存在,任何其他調用它的地方都不能使用存在類型(沒有不安全的未經檢查的轉換)。」你能舉一個簡單的例子嗎?我不完全明白你的意思。 – jhegedus
「在第一種情況下,A更簡單,但在第二種情況下,其客戶是這樣。」客戶如何更簡單?我不明白,你能舉個例子嗎? – jhegedus
@jhegedus查看編輯。 –