为什么避免被Scala';什么是抽象类型细化?

为什么避免被Scala';什么是抽象类型细化?,scala,path-dependent-type,abstract-type,Scala,Path Dependent Type,Abstract Type,我有一个关于抽象类型的Scala编程的第20.7章(MartinOdersky,LexPon和BillVenners)中的一个基本示例。下面的代码来自清单20.10,只是我添加了前一个示例表面上暗示的最后两行代码: class Food abstract class Animal { type SuitableFood <: Food def eat(food: SuitableFood) } class Grass extends Food class Cow extends A

我有一个关于抽象类型的Scala编程的第20.7章(MartinOdersky,LexPon和BillVenners)中的一个基本示例。下面的代码来自清单20.10,只是我添加了前一个示例表面上暗示的最后两行代码:

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
既然我无法在bossy(声明为动物)的“eat()”方法调用中放入任何东西来满足编译器的要求,为什么编译器甚至允许bossy声明为动物/实例化为奶牛?换句话说,允许对象声明/实例化(而不是方法调用)有什么可能的用途

考虑到抽象成员类型细化似乎有意允许OO编程中通常禁止的东西,Scala中是否有此功能的“最佳实践”?也许有人发现了杀手的用途

我非常希望看到这种行为有完美的意义。该特性的动机用例是什么,即声明一个抽象类型,然后在派生类中细化该类型,使子类型的类型比父类型的类型更细化

既然我无法在bossy(声明为动物)的“eat()”方法调用中放入任何东西来满足编译器的要求,为什么编译器甚至允许bossy声明为动物/实例化为奶牛

  • 有:
    专横。吃((新草)。代替[专横。适宜的食物]
    。当然,这并不意味着你应该写这样的代码

  • 即使没有,您也可以使用
    bossy
    做很多事情,而无需调用
    eat
    方法:将其放入
    列表
    ,获取其哈希代码,等等


  • 你还可以做其他有用的事情。如果你能证明它是合适的食物,你可以做一个
    动物
    食物
    。 当你能让一只动物呕吐时,你就知道他吐出来的东西都是他能吃的,因为他以前吃过的东西。你知道它是食物,即使你不确定它是草还是鱼。因此,您可以对每种
    食品进行操作

    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    abstract class Food { def name: String }
    class Grass extends Food { def name = "Grass" }
    abstract class Animal {
      type SuitableFood <: Food
      def eat(food: SuitableFood): Unit
      def throwUp: Option[SuitableFood]
    }
    
    class Cow extends Animal {
      type SuitableFood = Grass
      private[this] var digesting: List[Grass] = Nil
      def eat(food: Grass) {
        digesting = food :: digesting
      }
      def throwUp = digesting match {
        case Nil => None
        case food :: rest =>
          digesting = rest
          Some(food)
      }
    }
    
    def dispose(food: Food) = println(s"Disposing of some ${food.name}.")
    
    // Exiting paste mode, now interpreting.
    
    
    scala> val animal: Animal = { val cow = new Cow; cow.eat(new Grass); cow }
    animal: Animal = Cow@506dcf55
    
    scala> animal.throwUp foreach animal.eat  // can eat his own vomit :s
    
    scala> animal.throwUp foreach dispose  // I can dispose of all food
    Disposing of some Grass.
    
    scala>:粘贴
    //进入粘贴模式(按ctrl-D键完成)
    抽象类食物{def name:String}
    类Grass扩展食物{def name=“Grass”}
    抽象类动物{
    类型适合食品无
    案例食品::休息=>
    消化=休息
    一些(食物)
    }
    }
    def dispose(food:food)=println(s“Disposing of some${food.name}.”)
    //正在退出粘贴模式,现在正在解释。
    scala>val-animal:animal={val-cow=新牛;cow.eat(新草);cow}
    动物:动物=Cow@506dcf55
    scala>animal.throwUp foreach animal.eat//可以吃自己的呕吐物:s
    scala>animal.throwUp foreach dispose//我可以处理所有食物
    处理一些草。
    
    好的。这不是编译错误。您仍然可以在您的bossy val上进行模式匹配,以便能够获取其正确的子类型并对其调用正确的方法。
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    abstract class Food { def name: String }
    class Grass extends Food { def name = "Grass" }
    abstract class Animal {
      type SuitableFood <: Food
      def eat(food: SuitableFood): Unit
      def throwUp: Option[SuitableFood]
    }
    
    class Cow extends Animal {
      type SuitableFood = Grass
      private[this] var digesting: List[Grass] = Nil
      def eat(food: Grass) {
        digesting = food :: digesting
      }
      def throwUp = digesting match {
        case Nil => None
        case food :: rest =>
          digesting = rest
          Some(food)
      }
    }
    
    def dispose(food: Food) = println(s"Disposing of some ${food.name}.")
    
    // Exiting paste mode, now interpreting.
    
    
    scala> val animal: Animal = { val cow = new Cow; cow.eat(new Grass); cow }
    animal: Animal = Cow@506dcf55
    
    scala> animal.throwUp foreach animal.eat  // can eat his own vomit :s
    
    scala> animal.throwUp foreach dispose  // I can dispose of all food
    Disposing of some Grass.