亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

為什么這個示例不編譯,也就是(協、對、內)方差是如何工作的?

為什么這個示例不編譯,也就是(協、對、內)方差是如何工作的?

為什么這個示例不編譯,也就是(協、對、內)方差是如何工作的?從這個問題,有人能用Scala解釋一下以下情況嗎?class Slot[+T] (var some: T) {     //  DOES NOT COMPILE     //  "COVARIANT parameter in CONTRAVARIANT position"}我明白+T和T在類型聲明中(如果我使用T)。但是,如何編寫一個類,該類在其類型參數中是協變的,而不訴諸于創建非參數化?如何確保只能使用T?class Slot[+T] (var some: Object){       def get() = { some.asInstanceOf[T] }}編輯-現在將其歸結為以下幾點:abstract class _Slot[+T, V <: T] (var some: V) {     def getT() = { some }}這一切都很好,但我現在有兩個類型參數,其中我只想要一個。因此,我將再次提出這個問題:我怎么寫不變 Slot類,即協變它的類型?編輯2哦!我用var而不是val..以下是我想要的:class Slot[+T] (val some: T) { }
查看完整描述

3 回答

?
慕勒3428872

TA貢獻1848條經驗 獲得超6個贊

一般說來,協變類型參數允許在類是子類型時向下變化(或者,隨子類型而變化,因此是“co-”前綴)。更具體而言:

trait List[+A]

List[Int]List[AnyVal]因為IntAnyVal..這意味著您可以提供List[Int]當類型值為List[AnyVal]都是意料之中的。對于泛型來說,這確實是一種非常直觀的工作方式,但事實證明,在存在可變數據的情況下使用它是不健全的(破壞了類型系統)。這就是為什么泛型在Java中是不變的。使用Java數組(這些數組是錯誤的協變量)的不穩定的簡單示例:

Object[] arr = new Integer[1];arr[0] = "Hello, there!";

我們剛剛分配了一個類型的值String類型數組Integer[]..出于顯而易見的原因,這是個壞消息。Java的類型系統實際上允許在編譯時這樣做。JVM將“幫助”拋出ArrayStoreException在運行時。Scala的類型系統防止了此問題,因為Array類是不變的(聲明是[A]而不是[+A]).

請注意,還有另一種類型的差異稱為反向方差..這是非常重要的,因為它解釋了為什么協方差會引起一些問題。反方差實際上是協方差的對立面:參數是可變的。向上有亞型。雖然它確實有一個非常重要的應用程序:函數,但它并不常見,部分原因是它違反了直覺。

trait Function1[-P, +R] {
  def apply(p: P): R}

注意“-“對P類型參數這個聲明作為一個整體意味著Function1是逆變的P和協變R..因此,我們可以導出以下公理:

T1' <: T1
T2 <: T2'---------------------------------------- S-FunFunction1[T1, T2] <: Function1[T1', T2']

注意T1'的子類型(或同一類型)。T1,而相反的是T2T2'..英文本可閱讀如下:

函數A是另一個函數的子類型。B如果參數類型為A的參數類型的超級類型。B的返回類型A的返回類型的子類型。B.

這個規則的原因是留給讀者練習的(提示:考慮不同的情況,因為函數是子類型的,就像上面我的數組示例)。

使用您新發現的協方差和反向方差知識,您應該能夠了解為什么下面的示例將不編譯:

trait List[+A] {
  def cons(hd: A): List[A]}

問題是A是協變的,而cons函數的類型參數為不變量..因此,A改變了錯誤的方向。有趣的是,我們可以通過List逆變A,但是返回類型List[A]將無效,因為cons函數的返回類型為協變.

我們這里只有兩個選擇A不變量,丟失協方差的良好、直觀的子類型屬性,或(B)向cons方法,該方法定義A作為下限:

def cons[B >: A](v: B): List[B]

現在這是有效的。你可以想象A是向下變化的,但是B能夠向上變化AA是它的下界。通過這個方法聲明,我們可以A是協變的,一切都成功了。

注意,只有當我們返回List,它專門針對不太特定的類型。B..如果你想List可變的,因為你最終試圖分配類型的值,事情就會變壞。B類型變量A,這是編譯器不允許的。無論何時有可變性,都需要有某種類型的變體,這需要某種類型的方法參數,這意味著(與訪問器一起)意味著不變性。協方差適用于不可變數據,因為唯一可能的操作是訪問器,訪問器可以被賦予協變量返回類型。


查看完整回答
反對 回復 2019-07-05
?
白豬掌柜的

TA貢獻1893條經驗 獲得超10個贊

簡單地說,如果允許的話:

  class Slot[+T](var some: T) {
    def get: T = some   
  }

  val slot: Slot[Dog] = new Slot[Dog](new Dog)   
  val slot2: Slot[Animal] = slot  //because of co-variance 
  slot2.some = new Animal   //legal as some is a var
  slot.get ??

slot.get將在運行時拋出一個錯誤,因為它在轉換AnimalDog(哼!)

一般說來,變異與協方差和反向方差不太一致。這就是為什么所有Java集合都是不變的原因。


查看完整回答
反對 回復 2019-07-05
  • 3 回答
  • 0 關注
  • 479 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號