在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)
^
但是牛。饲料是草,所以为什么这不起作用?
答案 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)