在《 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-07-04 07:02:17 +08:00 via iPhone
class Fish extends Food
你已经指定 Fish 是可以被牛吃的一种食物了啊。 |
2
ech0x 2019-07-04 07:04:20 +08:00 via iPhone
名字只是一个代称,写什么都是没有问题的,类与类之间的关系才是重要的。
|
3
w4ngzhen OP @ech0x 这位老师您看哈,上述假设的地方假如成立,那么 Cow 确实有一个 eat(Grass)的方法,这个方法依然不能接受 Fish 实例呀
|
6
w4ngzhen OP @ech0x 所以这样不是更能够限定接受的参数类型吗,但是书中表示如果参数能够协变,反而会出现 cow eat new Fish 的情况
|
7
ech0x 2019-07-04 08:38:04 +08:00 via iPhone
class Cow extends Animal {
override def eat(food: Fish) = {} } 这样不就出现了 cow eat new Fish 的情况? |
8
ech0x 2019-07-04 08:39:18 +08:00 via iPhone
哦,我弄错了,问题不在这里。
|
9
ech0x 2019-07-04 08:42:00 +08:00 via iPhone
我知道问题在哪里了,你注意看 bessy 的类型,bessy 的类型不是 Cow 是 Animal
|
10
w4ngzhen OP @ech0x 额,是否是这样的, [错误假设] 假如成立的时候,能通过编译,但在运行时调用为 eat ( Grass )方法,所以会有转型出错这样的不安全情况?但是这样又说不通 override def eat(food: Food),cow 依然能够 eat Fish 的情况啊。
|
11
madeye 2019-07-04 09:48:28 +08:00
简单来说,你不能用
··· 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 final members named eat: def eat(food: Playground.this.Food): Unit ··· https://scastie.scala-lang.org/Gq2lJuhRTnCM8Q46BSmA6g |
13
w4ngzhen OP |
15
dcalsky 2019-07-04 10:38:32 +08:00 via Android
@w4ngzhen 没问题啊 只不过是你命名语义的问题。第二段代码,你声明了 Cow 可以 Eat Food,而 Fish 是 Food 的子类,所以 fish 可以作为参数传入。我举个例子好了,有一个 array[HTMLDOM],,你把 P,Button,Input 这些 HTMLDOM 的子类 add 进入都没问题。你的 Food 就是对应了 HTMLDOM,而 Fish 对应了这里的 Button,所以是没问题的。
|
16
madeye 2019-07-04 12:10:30 +08:00
"假设能够通过" 在英文里是虚拟语态,本意就是这件事是不可能,否则会造成不合理的结果。
··· 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,...”,翻译成 "但如果这都能编译过的话" 可能会更好一些。 |