为什么避免被Scala';什么是抽象类型细化?
我有一个关于抽象类型的Scala编程的第20.7章(MartinOdersky,LexPon和BillVenners)中的一个基本示例。下面的代码来自清单20.10,只是我添加了前一个示例表面上暗示的最后两行代码:为什么避免被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
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.