Scala理解中的“下界”

时间:2016-12-24 11:12:07

标签: 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. 因为Puppy不是狗,也不是超级狗     为什么允许animalDisplay.displayUptoDog(puppy)?一些真实的     usecase将帮助我更好地理解

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

  3. animalDisplay.displayUptoDog(human),其中Human不是超类 那么为什么它被允许和打印 “com.typeSystem.typeBound.lowerBound.Human@4554617c”
  4. animalDisplay.displayUptoDog(plant),其中Plant不在同一个地方 层次结构,那么为什么它也被允许和打印 “com.typeSystem.typeBound.lowerBound.Plant@74a14482”
  5. 让我知道我是否遗漏了一些东西

1 个答案:

答案 0 :(得分:0)

允许

animalDisplay.displayUptoDog(puppy),因为您可以将Puppy投射到Dog,如下所示:

animalDisplay.displayUptoDog(puppy: Dog)

现在您可能会问,如果您可以简单地将对象转发到T以使其适合,那么在方法签名中使用T的下限有什么意义呢?要回答这个问题,我认为最好看一个例子,其中下限确实有用甚至是必要的。

下限的一个非常常见的用例是,当您希望确保某些方法返回与某些其他类型相同的类型值时,例如在Option[A]中有一个方法:

def getOrElse[B >: A](default: ⇒ B): B

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

正如您在所有情况下所看到的,它的行为符合预期。在getOrElseABDog时调用Puppy始终会返回两个共同的类型,即Dog。< / p>