3

Odersky 等人在 Programming in 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)
         ^

但是 cow.Feed 是草,那么为什么这不起作用呢?

4

2 回答 2

8

这里的问题是你的 valcow的类型是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

于 2012-08-27T12:58:52.973 回答
3

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

在这条线上:

val cow: Animal = new Cow

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

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

val cow = new Cow
cow.eat(new Grass)
于 2012-08-27T12:56:16.440 回答