上界类型和正常类行为的差异 [英] Difference of Upper Bounded Type and normal class behavior
问题描述
我正在Scala中学习泛型,但我无法理解正常"类层次结构与上界"类型之间的区别.
I am studying Generics in Scala and I can't understand the difference between a "normal" class hierarchy and the Upper Bound type.
看下面的例子:笼子可以收到动物类,这意味着我可以通过动物类或狗类.上限参数也一样.它们之间的实际区别是什么?我什么时候应该使用其中一个?
Looking at the example below: Cage can receive the class Animal, which means that I can pass either the class Animal or the class Dog. The same is valid for the upper bound parameter. What is the practical difference between them? When should I use one or the other?
class Animal
class Dog extends Animal
class Cage(animal: Animal)
val cage = new Cage(new Dog)
class AnotherCage[A <: Animal](animal: A)
val anotherCage = new AnotherCage(new Dog)
推荐答案
animal
参数的 static 类型是一个区别,在前一种情况下,它在Animal
中键入为Animal
.在后一种情况下,将其键入为Dog
,因为类型参数A
被具体类型Dog
代替.要了解差异,请尝试向Dog
添加sound
方法,如下所示
One difference is in the static type of animal
parameter where in the former case it is typed as Animal
whilst in latter case it is typed as Dog
because the type parameter A
is substituted with concrete type Dog
. To see the difference try adding a sound
method to Dog
like so
class Animal
class Dog extends Animal {
def sound = "woof"
}
class Cage(val animal: Animal)
val cage = new Cage(new Dog)
class AnotherCage[A <: Animal](val animal: A)
val anotherCage = new AnotherCage(new Dog)
cage.animal.sound // error
anotherCage.animal.sound // ok
请注意,尽管animal
参数引用的运行时类是Dog
,但在第一种情况下编译器如何不了解sound
方法.
Note how compiler is not aware of sound
method in the first case despite the fact that the runtime class referenced by animal
argument is Dog
.
参数化类型可以提供更强的类型安全性,并有助于避免使用asInstanceOf
进行类型转换.例如,假设我们有一个Dog
和Cat
Parameterized types can provide stronger type-safety and help avoid the need for type casting with asInstanceOf
. For example, let's say we have a Dog
and a Cat
class Animal
class Dog extends Animal
class Cat extends Animal
,我们定义了一种仅打开包含Dog
s
and we define a method that opens only cages containing Dog
s
def openDogCage(cage: Cage): Dog =
if (cage.animal.isInstanceOf[Dog]) cage.animal.asInstanceOf[Dog]
else throw new IllegalArgumentException
def openAnotherDogCage(cage: AnotherCage[Dog]): Dog = cage.animal
但错误地为笼子提供了Cat
but erroneously provide a cage with a Cat
val dog: Dog = openDogCage(new Cage(new Cat)) // runtime error
val dog: Dog = openAnotherDogCage(new AnotherCage(new Cat)) // compile-time error
然后注意参数化类型是如何在程序运行之前在编译时捕获错误的.还请注意,在仅使用子类型时,在openDogCage
的定义中我们必须手动执行asInstanceOf
的类型转换,以使编译器确信该方法返回了Dog
.
then notice how parameterzied types caught the error at compile-time before the program even ran. Also notice how in definition of openDogCage
when using just subtyping we had to manually perform a type cast with asInstanceOf
to convince the compiler that method returns a Dog
.
这篇关于上界类型和正常类行为的差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!