我从一本Scala食谱上看到了一个例子。我理解了这个例子,并做了一些修改,以确保我彻底地理解了这个示例。
代码示例,
trait Animal {
def speak
}
class Dog(var name: String) extends Animal {
def speak { println("Dog says woof") }
}
class SuperDog(name: String) extends Dog(name) {
override def speak { println("I'm a SuperDog") }
}
// solution 1
class Container[+T](val elem : T)
def makeDogsSpeak(dogHouse: Container[Dog]) {
dogHouse.elem.speak
}
val superDogHouse = new Container(new SuperDog("Wonder Dog"))
makeDogsSpeak(superDogHouse) // solution 2
class Container[T](val elem : T) // remove covariant from type
def makeDogsSpeak[U <: Dog](dogHouse: Container[U]) {
dogHouse.elem.speak
}
val superDogHouse = new Container(new SuperDog("Wonder Dog"))
makeDogsSpeak(superDogHouse)。
class Container[T](val elem : T) // remove covariant from type
val superDogHouse = new Container(new SuperDog("Wonder Dog"))
makeDogsSpeak(superDogHouse) // compilation error但如果我这么做
makeDogsSpeak(new Container(new SuperDog("Wonder Dog"))) // superDogHouse removed编译器编译了。这里发生了什么事?不是“相同”的密码吗?谢谢
发布于 2014-06-11 11:49:20
关于方差声明(问题1):
申报-一方差异:
class Container[+T](val elem : T)使用-侧差异:
def makeDogsSpeak(dogHouse: Container[_ <: Dog])使用声明或使用侧方差表示法取决于您的代码设计。在某些情况下,方法可以是泛型的(并且可以使用简短表示法的类型推断),但在某些情况下,方法不能是泛型的。
对于某些类来说,参数约束只是实现良好设计的一种方法。例如:
trait List[+A]
object Nil extends List[Nothing]使用:
val xs : List[Int] = Nil // will not possible in case List[A]在某些情况下,还需要混合声明&使用侧变量,因为参数在容器中的位置与方差有关。
共变位置参数:
trait C[+T] {
def get : T
}反变位置:
trait C[-T] {
def set(x : T): Unit
}但不是:
trait C[+T] {
def get : T
def set(x : T): Unit // wrong position of type T
}通过混合声明-&使用侧方差来修正:
trait C[+T] {
def get : T
def set[TT >: T](x : TT): Unit // ok
}关于问题2
考虑到类型推断的规则,对于编译器,代码如下所示:
val superDogHouse = new Container[SuperDog](new SuperDog("Wonder Dog"))
makeDogsSpeak(superDogHouse) // compilation error和
makeDogsSpeak(new Container[Dog](new SuperDog("Wonder Dog")))它在第一种情况下工作而在第二种情况下不起作用的原因是一种容器。
https://stackoverflow.com/questions/24161491
复制相似问题