简体   繁体   English

上界类型与正常 class 行为的差异

[英]Difference of Upper Bounded Type and normal class behavior

I am studying Generics in Scala and I can't understand the difference between a "normal" class hierarchy and the Upper Bound type.我正在研究 Scala 中的 Generics ,我无法理解“正常” class 层次结构和上界类型之间的区别。

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.看下面的例子:Cage 可以接收 class Animal,这意味着我可以通过 class Animal 或 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)

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 .一个区别在于static类型的animal参数,在前一种情况下,它被键入为Animal ,而在后一种情况下,它被键入为Dog ,因为类型参数A被替换为具体类型Dog To see the difference try adding a sound method to Dog like so要查看差异,请尝试像这样向Dog添加sound方法

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

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 .请注意,尽管animal参数引用的运行时 class 是Dog ,但编译器在第一种情况下如何不知道sound方法。

Parameterized types can provide stronger type-safety and help avoid the need for type casting with asInstanceOf .参数化类型可以提供更强的类型安全性,并有助于避免使用asInstanceOf进行类型转换。 For example, let's say we have a Dog and a Cat例如,假设我们有一只Dog和一只Cat

class Animal
class Dog extends Animal
class Cat extends Animal

and we define a method that opens only cages containing Dog s我们定义了一个只打开包含Dog的笼子的方法

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

but erroneously provide a cage with a Cat但错误地提供了一个有Cat的笼子

val dog: Dog = openDogCage(new Cage(new Cat))               // runtime error
val dog: Dog = openAnotherDogCage(new AnotherCage(new Cat)) // compile-time error

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 .还要注意在openDogCage的定义中,当仅使用子类型时,我们必须手动使用asInstanceOf执行类型转换,以使编译器相信该方法返回Dog

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM