我在Scala编程的第20.7章(Martin Odersky,Lex Spoon和Bill Venners)中有关于抽象类型主题的基本示例。下面的代码是从清单20.10,除了我添加了似乎表面上通过在前面的例子中隐含的最后两行:为什么要避免被Scala的抽象类型细化困住?
class Food
abstract class Animal {
type SuitableFood <: Food
def eat(food: SuitableFood)
}
class Grass extends Food
class Cow extends Animal {
type SuitableFood = Grass
override def eat(food: Grass) {}
}
class Fish extends Food
val bossy: Animal = new Cow // If the compiler were helpful, this would error.
bossy.eat(new Grass) // error!
// type mismatch; found: Grass, required: bossy.SuitableFood
正如我如上所述,其中颐指气使被声明为动物的两条线是不实际在这个例子中,但似乎是一个非常合理的概念上的飞跃。在抽象类Animal(被称为bossy的类型)的层次上,类型成员SuitableFood仍然是抽象的。因此,即使看起来好像在方法调用时需要路径依赖类型,编译器也不会满足要求。
如果我宣布我的VAL为类型奶牛,方法调用的作品,如下:
val bessy: Cow = new Cow
bessy.eat(new Grass) // happy-happy
鉴于有什么我可以把在'吃()方法调用的霸道(声明为动物)以满足编译器,为什么编译器甚至允许bossy被声明为Animal /实例化为Cow?换句话说,允许对象声明/实例化,但不包括方法调用,有什么可能的用途?
鉴于抽象成员类型精炼似乎故意允许在面向对象编程中被禁止的东西,在Scala中是否存在此功能的“最佳实践”?也许有人找到了杀手锏?
我非常希望看到这种行为是非常有意义的。这个特性的动机用例是什么,即声明一个抽象类型,然后在派生类中细化该类型,使得该子类型具有比超类型更精确的类型?
好吧。这不是编译错误。你仍然可以在你的bossy val上匹配模式,以便能够获得正确的子类型并在其上调用正确的方法。 – Falmarri
这已被问到[这里](http://stackoverflow.com/questions/20070998/abstract-type-in-scala),[here](http:// stackoverflow。com/questions/20754143/no-dynamic-binding-when-abstract-type-involved-in-scala),[here](http://stackoverflow.com/questions/32161100/scala-types-class-a-is不等于这里t是is型ta),和[这里](http://stackoverflow.com/questions/37756383/path-dependent-types-example-doesnt-work )。 – jwvh