方法参数中的抽象类型

时间:2012-08-27 12:29:47

标签: scala generics types abstract-type

在Odersky等人的Scala编程中有一个关于抽象类型的简单例子,但它似乎没有遵循它的逻辑结论[现在编辑以使其成为我的确切代码]:

class Food
class Grass extends Food
class FishFood extends Food

abstract class Animal {
  type Feed <: Food
  def eat(food: Feed)
}

class Cow extends Animal {
  type Feed = Grass
  override def eat(food: Grass) = {}
}

class Test extends App {
  val cow: Animal = new Cow
  cow.eat(new FishFood)
  cow.eat(new Grass)
}

他们解释说这会阻止我这样做(如上所述):

val cow: Animal = new Cow
cow.eat(new FishFood)

到目前为止一切顺利。但下一个自然步骤似乎也不起作用:

cow.eat(new Grass)

我收到编译错误:

type mistmatch;
found : Grass
required: Test.this.cow.Feed
 cow.eat(new Grass)
         ^

但是牛。饲料是草,所以为什么这不起作用?

2 个答案:

答案 0 :(得分:8)

这里的问题是你的val cow被输入为Animal而不是Cow,所以编译器知道的是它的eat方法需要一些特定的子类型Food,但它不知道哪个,特别是它无法证明该类型等于Grass

您可以通过询问方法的eta-expansion来了解方法类型(从Animal看与Cow相比)的差异

scala> val cow: Animal = new Cow
cow: Animal = Cow@13c02dc4

scala> cow.eat _
res12: cow.Feed => Unit = <function1>

scala> cow.asInstanceOf[Cow].eat _
res13: Grass => Unit = <function1>

您会注意到,在第二种更精确类型的情况下,编译器将该方法视为采用类型为Grass的参数而不是抽象类型cow.Feed

答案 1 :(得分:3)

它应该以这种方式失败 - 实际上,我认为它在Scala编程中有解释(第2版,第460页)。

在这一行:

val cow: Animal = new Cow

你告诉编译器假设cow可能是任何动物,包括鱼 - 而且它肯定会对吃草没有好处!

如果您让编译器推断出正确的类型,它将编译:

val cow = new Cow
cow.eat(new Grass)