2017-07-01 68 views
0

簡單協方差示例:爲什麼asInstance可以工作?斯卡拉:我如何得到這個玩具協變的例子工作?

class Fruit(name: String) { def get_name = name} 
class Apple(name: String) extends Fruit(name) 
class Orange(name: String) extends Fruit(name) 
class BigOrange(name:String) extends Orange(name) 

    // Contrived but simple covariant box with some utility functions 
    class Box[+T <: Fruit] { 
    def foo[ U >: T] (item: U): String = item.asInstanceOf[T].get_name 
    } 

    val f = new Fruit("fruit") 
    val a = new Apple("apple") 
    val o = new Orange("orange") 

    // Error. Makes sense apples cannot be casted to oranges 
    println(a.asInstanceOf[Orange]) 


    val bo1 = new Box[Orange] 
    println(bo1.foo(a)) // Returns Apple ! How was an apple seemingly casted to an orange? 

那麼爲什麼最後一行工作?是不是要求通過的蘋果被鑄造成橙色的邏輯?

第二個問題:爲什麼此代碼會給我get_name無法識別的錯誤?

class Box[+T <: Fruit] (item: T) { 
    val contents = item 
    def foo[ U >: T] (item: U): String = item.get_name 
} 

的[+ T <:水果]之間和U>:T,is'nt它明顯,項應該有一個GET_NAME?爲什麼錯誤?

+0

當你遇到需要使用'asInstanceOf'時,這通常表明你做錯了什麼。 'foo'的聲明方式,你可以稱它爲'foo(1200)'或者'foo(「bar」)'。我懷疑這就是你想要的......但是你真正想要的是什麼?你究竟想在這裏做什麼?例如,爲什麼不只是'def foo(item:T)= item.get_name'開始? – Dima

+0

我想通過問自己爲什麼有些作品來學習。不,富(120)不起作用 – user7938511

+0

「作品」我的意思是,它編譯。 type參數是無用的,這個函數將接受任何時候的參數,然後在運行時拋出異常。斯卡拉是一種嚴格類型的語言,這完全不是它應該如何使用的。 – Dima

回答

1

在[+ T <:Fruit]和U>:T之間,是不是很明顯,item應該有一個get_name?

當然不是。例如,U = Any滿足約束且不具有get_name成員。

+0

1.是否有沿着U>的線約束的方法:T _and_ U!=任何_and_ U <:水果?如果那樣的話,它會在未來嗎? – user7938511

+0

您可以合併U:T和U U:Fruit:U <: Fruit > T。而'U <:Fruit'已經暗示'U!= Any'。 –

1

asInstanceOf[T]實際上什麼都不做,因爲BoxT被清除。你也應該從編譯器得到警告。

1

這裏的問題...

class Box[+T <: Fruit] (item: T) { 
    val contents = item 
    def foo[U >: T] (item: U): String = item.get_name 
} 

...是,你遮蔽一個item另一個。第一個,item: T,確實有一個get_name成員,編譯器可以識別,但第二個,item: U不。它可能是Fruit的父級或超級類別,這意味着不能保證get_name成員。