我试图理解scala中的"下限"。请找到以下示例
class Animal
class Dog extends Animal
class Puppy extends Dog
class Human extends Animal
class Plant
class AnimalDisplay{
def displayUptoDog [T >: Dog](t: T){
println(t)
}
def displayUptoAnimal [T >: Animal](t: T){
println(">>"+t.getClass())
}
}
object ScalaLowerBoundsTest {
def main(args: Array[String]) {
val animal = new Animal
val dog = new Dog
val puppy = new Puppy
val human=new Human
val plant = new Plant
val animalDisplay = new AnimalDisplay
println("Upto Animal")
animalDisplay.displayUptoAnimal(animal)
animalDisplay.displayUptoAnimal(dog)
animalDisplay.displayUptoAnimal(puppy)
animalDisplay.displayUptoAnimal(human)
animalDisplay.displayUptoAnimal(plant)
println("Upto Dog")
animalDisplay.displayUptoDog(animal)
animalDisplay.displayUptoDog(dog)
animalDisplay.displayUptoDog(puppy)
// prints: com.typeSystem.typeBound.lowerBound.Puppy@1b6d3586
animalDisplay.displayUptoDog(human)
//print:com.typeSystem.typeBound.lowerBound.Human@4554617c
animalDisplay.displayUptoDog(plant)
//prints:com.typeSystem.typeBound.lowerBound.Plant@74a14482
}
}
我的问题是
由于小狗不是狗,也不是超级狗类,那么 为什么允许
animalDisplay.displayUptoDog(puppy)
?一些真实的 用例将帮助我更好地理解如果
(animalDisplay.displayUptoDog(puppy))
是允许的,那么它 应该 打印com.typeSystem.typeBound.lowerBound.Dog@xxxxx
而不是com.typeSystem.typeBound.lowerBound.Puppy@1b6d3586
- animalDisplay.displayUptoDog(human),其中人类不是超类 的狗那么为什么它被允许和打印 "com.typeSystem.typeBound.lowerBound.Human@4554617c">
- animalDisplay.displayUptoDog(plant),其中 Plant 不在同一 层次结构,那么为什么它也被允许并打印 "com.typeSystem.typeBound.lowerBound.Plant@74a14482">
如果我错过了什么,请告诉我
>animalDisplay.displayUptoDog(puppy)
是允许的,因为您可以将Puppy
转换为Dog
,如下所示:
animalDisplay.displayUptoDog(puppy: Dog)
现在你可能会问,如果你可以简单地将对象向上转换为T
以适合它,那么在方法签名中使用T
下限有什么意义?要回答这个问题,我认为最好看一个例子,其中下限确实有用甚至必要。
下限的一个非常常见的用例是,当您希望确保某些方法返回与其他类型通用的类型值时,例如,Option[A]
有一个方法:
def getOrElse[B >: A](default: ⇒ B): B
如果我们想要它A
和B
常见的类型 ,唯一合理的选择是当A
是B
的子类型时。在相反的情况下(B <: A
),如果该选项是Some[A]
,则无法返回A
A
因为它不是B
的子类型。
下面是一个示例,当我们将其应用于Dog
类层次结构时,它是如何工作的:
val d1 = Some(dog).getOrElse(puppy)
d1: Dog = $sess.cmd1$Dog@55e02661
val d2 = (None: Option[Dog]).getOrElse(puppy)
d2: Dog = $sess.cmd2$Puppy@420068a
val d3 = Some(puppy).getOrElse(dog)
d3: Dog = $sess.cmd2$Puppy@420068a
val d4 = (None: Option[Puppy]).getOrElse(dog)
d4: Dog = $sess.cmd1$Dog@55e02661
正如您在所有情况下所看到的,它的行为都符合预期。当A
和B
Dog
或Puppy
时调用getOrElse
始终返回它们共同的类型,即Dog
。