理解斯卡拉"lower bound"

  • 本文关键字:lower bound scala
  • 更新时间 :
  • 英文 :


我试图理解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
}
}

我的问题是

由于小狗不是狗,也不是
  1. 超级狗类,那么 为什么允许animalDisplay.displayUptoDog(puppy)?一些真实的 用例将帮助我更好地理解

  2. 如果(animalDisplay.displayUptoDog(puppy))是允许的,那么它 应该 打印com.typeSystem.typeBound.lowerBound.Dog@xxxxx而不是com.typeSystem.typeBound.lowerBound.Puppy@1b6d3586

  3. animalDisplay.displayUptoDog(human),其中人类不是超类 的狗那么为什么它被允许和打印 "com.typeSystem.typeBound.lowerBound.Human@4554617c">
  4. 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

如果我们想要它AB常见的类型 ,唯一合理的选择是当AB的子类型时。在相反的情况下(B <: A),如果该选项是Some[A],则无法返回AA因为它不是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

正如您在所有情况下所看到的,它的行为都符合预期。当ABDogPuppy时调用getOrElse始终返回它们共同的类型,即Dog

最新更新