关于《Scala 编程(3rd)》中, 20.6 抽象类型 P424 的疑问 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zhenwang
V2EX    Scala

关于《Scala 编程(3rd)》中, 20.6 抽象类型 P424 的疑问

  •  
  •   zhenwang 2019 年 7 月 3 日 7001 次点击
    这是一个创建于 2440 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在《 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 // 能通过编译且运行 

    小弟不才,一直没理解,希望各位大佬轻喷

    18 条回复    2019-07-04 17:32:20 +08:00
    ech0x
        1
    ech0x  
       2019 年 7 月 4 日 via iPhone
    class Fish extends Food
    你已经指定 Fish 是可以被牛吃的一种食物了啊。
    ech0x
        2
    ech0x  
       2019 年 7 月 4 日 via iPhone
    名字只是一个代称,写什么都是没有问题的,类与类之间的关系才是重要的。
    zhenwang
        3
    zhenwang  
    OP
       2019 年 7 月 4 日 via iPhone
    @ech0x 这位老师您看哈,上述假设的地方假如成立,那么 Cow 确实有一个 eat(Grass)的方法,这个方法依然不能接受 Fish 实例呀
    ech0x
        4
    ech0x  
       2019 年 7 月 4 日 via iPhone
    @w4ngzhen 别叫我老师我其实不会 Scala。
    仍然不接受 Fish 所以呢?
    ech0x
        5
    ech0x  
       2019 年 7 月 4 日 via iPhone
    @w4ngzhen 我没明白你想表达什么。
    zhenwang
        6
    zhenwang  
    OP
       2019 年 7 月 4 日 via iPhone
    @ech0x 所以这样不是更能够限定接受的参数类型吗,但是书中表示如果参数能够协变,反而会出现 cow eat new Fish 的情况
    ech0x
        7
    ech0x  
       2019 年 7 月 4 日 via iPhone
    class Cow extends Animal {
    override def eat(food: Fish) = {}
    }
    这样不就出现了
    cow eat new Fish 的情况?
    ech0x
        8
    ech0x  
       2019 年 7 月 4 日 via iPhone
    哦,我弄错了,问题不在这里。
    ech0x
        9
    ech0x  
       2019 年 7 月 4 日 via iPhone
    我知道问题在哪里了,你注意看 bessy 的类型,bessy 的类型不是 Cow 是 Animal
    zhenwang
        10
    zhenwang  
    OP
       2019 年 7 月 4 日
    @ech0x 额,是否是这样的, [错误假设] 假如成立的时候,能通过编译,但在运行时调用为 eat ( Grass )方法,所以会有转型出错这样的不安全情况?但是这样又说不通 override def eat(food: Food),cow 依然能够 eat Fish 的情况啊。
    madeye
        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
    dcalsky
        12
    dcalsky  
       2019 年 7 月 4 日 via Android
    @w4ngzhen 为什么不编译一下呢
    zhenwang
        13
    zhenwang  
    OP
       2019 年 7 月 4 日
    @dcalsky
    @madeye
    两位老师,这个我自己已经写过了并且也能理解。现在核心就是不能理解书上说的假设能够通过编译后的解释,就拿我第二段代码来说,能够通过编译且能正常运行,这个时候就违背了语义了呀( cow eat Fish ),现在书上意义就是说,我们 [不能] 通过参数协变来 override 超类的方法,因为如果那样,就会出现 cow eat Fish 的情况;但是在我那段代码中(第二段):我也没有使用错误的 override,但是依然出现了 cow eat Fish 的情况。
    ech0x
        14
    ech0x  
       2019 年 7 月 4 日 via iPhone
    @madeye 惊现 madeye 大佬。
    dcalsky
        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,所以是没问题的。
    madeye
        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,...”,翻译成 "但如果这都能编译过的话" 可能会更好一些。
    zhenwang
        17
    zhenwang  
    OP
       2019 年 7 月 4 日
    @madeye 但是我还是很纠结这个的描述啊,您说“本意就是这件事是不可能,否则会造成不合理的结果。”但是我使用正确的方式 override,依然是不合理的结果呀(见我的第二段代码)。
    madeye
        18
    madeye  
       2019 年 7 月 4 日   1
    @w4ngzhen 因为你改变了原来代码的语意,cow 吃的 grass,而不是泛指的 food。严格来说来说,第二段代码算是个 bug,因为没有定义清楚 eat 这个函数所接受的类型。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3175 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 14:10 PVG 22:10 LAX 07:10 JFK 10:10
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86