Scala 专题教程-抽象成员(6): 抽象类型

jerry Scala 2015年11月25日 收藏

在本专题开始,我们看到“Type T?的用法,这是声明一个抽象类型,本篇介绍这种声明的意义和用途。和其它类型的抽象类型一样,抽象类型定义也是定义了一个“占位符”类型,其具体定义由其子类声明。不同的子类可以定义不同T的具体类型。
下面我们通过一个例子来说明抽象类型的用法,假定你需要为动物的饮食习性建模, 你可能会定义如下的数据结构:

  1. class Food
  2. abstract class Animal {
  3. def eat(food: Food)
  4. }

然后呢可能需要实现两个不同的实类对于与牛和草 Cows和Grass

  1. class Grass extends Food
  2. class Cow extends Animal {
  3. override def eat(food: Grass) {}
  4. }

但是这段代码编译不通过:

  1. <console>:13: error: class Cow needs to be abstract, since method eat in class Animal of type (food: Food)Unit is not defined
  2. (Note that Food does not match Grass: class Grass is a subclass of class Food, but method parameter types must match exactly.)
  3. class Cow extends Animal {
  4. ^
  5. <console>:14: error: method eat overrides nothing.
  6. Note: the super classes of class Cow contain the following, non final members named eat:
  7. def eat(food: Food): Unit
  8. override def eat(food: Grass) {}

怎么会出错呢,这是因为类Cow中的eat不能重载其父类,这是因为参数类型不一致,Animal中food类型为Food,而Cow中类型为Grass。 仅管有人会说Grass是Food的子类,编译器没有必要这么严格。但是如果编译器允许这种情况存在,那么很快就出现新问题了:

假定前面的编译没有问题,我们在定义一个Fish类

  1. class Fish extends Food
  2. val bessy: Animal = new Cow
  3. bessy eat (new Fish)

问题来了,我们给牛喂了鱼。如果前面的Cow可以编译通过的话,这段代码也是合法的,但结果却显然不对,因此编译器编译不通过Cow是有道理的。
对于这个问题,我们可以通过抽象类型来解决,哪种动物吃哪种食物由动物决定:

  1. class Food
  2. abstract class Animal {
  3. type SuitableFood <: Food
  4. def eat(food:SuitableFood)
  5. }
  6.  

当定义新的Animal子类时,动物只能吃合适的食物,而Animal 类本身不能决定那种食物合适,因此我们使用抽象类型定义。 但这个抽象类型有类型上界限制,表示Animal子类中使用的SuitableFood 必须是Food的子类。

我们重新定义Cow如下:

  1. class Grass extends Food
  2. class Cow extends Animal {
  3. type SuitableFood = Grass
  4. override def eat(food:Grass) {}
  5. }
  6.  

你现在再试试喂鱼给牛看看:

  1. scala> class Fish extends Food
  2. defined class Fish
  3.  
  4. scala> val bessy :Animal = new Cow
  5. bessy: Animal = Cow@a0992a
  6.  
  7. scala> bessy eat (new Fish)
  8. <console>:14: error: type mismatch;
  9. found : Fish
  10. required: bessy.SuitableFood
  11. bessy eat (new Fish)
  12. ^
  13.