Scala n00b在这里。很确定我理解PDT,但是确定并遇到了问题;这里是上一个问题Scala types: Class A is not equal to the T where T is: type T = A,其中包含示例代码,我将在此处重现:
1: class Food
2: class Fish extends Food
3: class Grass extends Food
4:
5: abstract class Animal {
6: type SuitableFood <: Food
7: def eat(food: SuitableFood)
8: }
9:
10: class Cow extends Animal {
11: type SuitableFood = Grass
12: override def eat(food: Grass) {}
13: }
14:
15: val bessy: Animal = new Cow // [1]
16:
17: bessy eat (new bessy.SuitableFood) // [2]
原始海报说这个编译,我认为应该,但它不会。如果我将它粘贴到scala REPL中,它会成功创建bessy [1]:
scala> val bessy: Animal = new Cow
bessy: Animal = Cow@165b8a71
但是[2],给了我一个我不理解的错误:
scala> bessy.eat(bessy.SuitableFood)
<console>:17: error: value SuitableFood is not a member of Animal
bessy.eat(bessy.SuitableFood)
^
如果我将其粘贴到文件中并且“scalac&#39;它,我也一样。为什么? bessy
是一个牛对象,其中定义了type SuitableFood = Grass
,bessy.SuitableFood
是一个类类型(不是吗?)。
怎么了?
答案 0 :(得分:2)
new
中缺少(new bessy.SuitableFood)
。
解决此问题后,bessy
被定义为类型Animal
,而不是Cow
,因此编译器不会知道{{ 1}}是bessy.SuitableFood
:它只是一个抽象类型,因此Grass
不起作用(如new bessy.SuitableFood
不是new A
时类型参数)。例如。考虑A
的某些其他子类型可以声明Animal
,而type SuitableFood = Food
是非法的。
我已经检查了,它确实在2.10.6中编译,但我相信这是一个修复过的错误。
因此,我认为“新的bessy.SuitableFood”将返回一个合适的食物,因为.SuitableFood将是一种虚拟类型,所以当'Cow'然后'SuitableFood'将是'草'。如果他们不这样做,我不会看到PDT的价值。
这里PDT的重点是,如果你做有一个new Food
,bessy.SuitableFood
可以吃掉它;并且她不能吃bessy
(除非编译器静态知道它是一个子类型)。但是这个例子没有给出产生spot.SuitableFood
的任何方法,因为没有理由假设(并且无法告诉编译器)bessy.SuitableFood
是一个带有公共无参数构造函数的类。您可以通过向type SuitableFood
添加方法来修复它:
Animal
现在abstract class Animal {
type SuitableFood <: Food
def eat(food: SuitableFood)
def newSuitableFood(): SuitableFood
}
class Cow extends Animal {
...
def newSuitableFood() = new Grass
}
将编译并运行。