
在《 Scala 编程( 3rd )》中,20.6 抽象类型这一节中,本人有个非常不解的地方,书中提到:
class Food abstract class Animal { def eat(food: Food) } class Grass extends Food class Cow extends Animal { override def eat(food: Grass) = {} // 这不能编译 } // 如果能的话... class Fish extends Food val bessy: Animal = new Cow bessy eat (new Fish) // ...你就能给牛吃草了 本人理解 override 超类方法,方法参数是不支持协变的,但是上文假设通过编译,"bessy eat (new Fish)"不是本来就不能运行吗? Fish 本来就不能上转型为 Grass 呀。何况如下重写 eat 方法岂不是同样有这个问题?
class Cow extends Animal { override def eat(food: Food): Unit = {} } val cow = new Cow cow eat new Fish // 能通过编译且运行 小弟不才,一直没理解,希望各位大佬轻喷
1 ech0x 2019 年 7 月 4 日 via iPhone class Fish extends Food 你已经指定 Fish 是可以被牛吃的一种食物了啊。 |
2 ech0x 2019 年 7 月 4 日 via iPhone 名字只是一个代称,写什么都是没有问题的,类与类之间的关系才是重要的。 |
3 zhenwang OP @ech0x 这位老师您看哈,上述假设的地方假如成立,那么 Cow 确实有一个 eat(Grass)的方法,这个方法依然不能接受 Fish 实例呀 |
6 zhenwang OP @ech0x 所以这样不是更能够限定接受的参数类型吗,但是书中表示如果参数能够协变,反而会出现 cow eat new Fish 的情况 |
7 ech0x 2019 年 7 月 4 日 via iPhone class Cow extends Animal { override def eat(food: Fish) = {} } 这样不就出现了 cow eat new Fish 的情况? |
8 ech0x 2019 年 7 月 4 日 via iPhone 哦,我弄错了,问题不在这里。 |
9 ech0x 2019 年 7 月 4 日 via iPhone 我知道问题在哪里了,你注意看 bessy 的类型,bessy 的类型不是 Cow 是 Animal |
10 zhenwang OP @ech0x 额,是否是这样的, [错误假设] 假如成立的时候,能通过编译,但在运行时调用为 eat ( Grass )方法,所以会有转型出错这样的不安全情况?但是这样又说不通 override def eat(food: Food),cow 依然能够 eat Fish 的情况啊。 |
11 madeye 2019 年 7 月 4 日 简单来说,你不能用 def eat(food: Grass) 去 override def eat(food: Food) 这两个 function 的 signature 并不一样,编译时就会报错。 method eat overrides nothing. Note: the super classes of class Cow contain the following, non finalmembers named eat: def eat(food: Playground.this.Food): Unit https://scastie.scala-lang.org/Gq2lJuhRTnCM8Q46BSmA6g |
13 zhenwang OP |
15 dcalsky 2019 年 7 月 4 日 via Android @w4ngzhen 没问题啊 只不过是你命名语义的问题。第二段代码,你声明了 Cow 可以 Eat Food,而 Fish 是 Food 的子类,所以 fish 可以作为参数传入。我举个例子好了,有一个 array[HTMLDOM],,你把 P,Button,Input 这些 HTMLDOM 的子类 add 进入都没问题。你的 Food 就是对应了 HTMLDOM,而 Fish 对应了这里的 Button,所以是没问题的。 |
16 madeye 2019 年 7 月 4 日 "假设能够通过" 在英文里是虚拟语态,本意就是这件事是不可能,否则会造成不合理的结果。 class Food abstract class Animal { def eat(food: Food) } class Grass extends Food class Cow extends Animal { override def eat(food: Grass) = {} // This won't compile, } // but if it did,... class Fish extends Food val bessy: Animal = new Cow bessy eat (new Fish) // ...you could feed fish to cows. 英文原文是 “ but if it did,...”,翻译成 "但如果这都能编译过的话" 可能会更好一些。 |