2017-07-01 12 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成员。