在使用类型参数或泛型时想要运行时多态性?
Want runtime polymorphism while using type parameter or generic?
下面是关于"animal eats food"的故事,还有猫吃鱼
class Food
abstract class Animal {
type F
def eat(food: F)
}
class Fish extends Food
class Cat extends Animal {
type F = Fish
def eat(fish: F) {
println("eat " + fish.getClass.getSimpleName)
}
}
(new Cat).eat(new Fish) //eat Fish
val animal: Animal = new Cat
animal.eat(new Fish) //error: type mismatch
现在我已经使用了抽象类型成员(或类型参数),我 失去 runtime polymorphism
(最后一行)。 (使用基本类型 Animal 来键入任意子类型和 运行 没有问题。)
否则我可以从 Animal 中删除类型参数并在 Cat 中进行类型检查:
abstract class Animal {
def eat(food: Food)
}
class Cat extends Animal {
def eat(food: Food) {
food match {
case fish: Fish => println("eat" + fish)
case _ => throw new IllegalArgumentException("I only eat fish")
}
}
}
但我想为他们打字更好。
那么我可以在使用类型参数/泛型时保留 运行时间多态性吗?
我不确定这是否是最佳方法,但它似乎有效。您可以允许将任何种类的食物传递给动物冒着 class 抛出异常的风险,并在发生时进行处理。
class Food
abstract class Animal {
type SuitableFood <: Food
def eat(food: SuitableFood)
def eatWithExceptionHandling(food: Food) {
try {
eat(food.asInstanceOf[SuitableFood])
}
catch {
case ex: ClassCastException => println("Wrong food")
}
}
}
class Grass extends Food
class Fish extends Food
class Cow extends Animal {
type SuitableFood = Grass
override def eat(food: Grass) {
println("Cow eating grass")
}
}
class Cat extends Animal {
type SuitableFood = Fish
override def eat(food: Fish) {
println("Cat eating fish")
}
}
val (cow, cat, grass ,fish) = (new Cow, new Cat, new Grass, new Fish)
cow.eat(grass) //"Cow eating grass"
cat.eat(fish) //"Cat eating fish"
//cow.eat(fish) // error: type mismatch
cow.eatWithExceptionHandling(grass) //"Cow eating grass"
cow.eatWithExceptionHandling(fish) //"Wrong food"
Now that I have used abstract-type member (or type-parameter) , I lose the runtime polymorphism (at last line). (that using base type Animal to typing arbitrary subtypes and run with no problem.)
不,您可以用其子类型替换 Animal
(在这种情况下,并非总是如此!),但反之则不行。如果可以的话,您也可以使用 Object
,因为它也是 Cat
:
的基本类型
val object: Object = new Cat
object.eat(new Fish)
希望您明白为什么这不应该编译。
或者你可以换一种说法:应该
val animal: Animal = makeAnAnimal()
animal.eat(new Fish)
编译?如果您认为答案是 "yes",请考虑 makeAnAnimal()
可以 return 一个 Cow
。
下面是关于"animal eats food"的故事,还有猫吃鱼
class Food
abstract class Animal {
type F
def eat(food: F)
}
class Fish extends Food
class Cat extends Animal {
type F = Fish
def eat(fish: F) {
println("eat " + fish.getClass.getSimpleName)
}
}
(new Cat).eat(new Fish) //eat Fish
val animal: Animal = new Cat
animal.eat(new Fish) //error: type mismatch
现在我已经使用了抽象类型成员(或类型参数),我 失去 runtime polymorphism
(最后一行)。 (使用基本类型 Animal 来键入任意子类型和 运行 没有问题。)
否则我可以从 Animal 中删除类型参数并在 Cat 中进行类型检查:
abstract class Animal {
def eat(food: Food)
}
class Cat extends Animal {
def eat(food: Food) {
food match {
case fish: Fish => println("eat" + fish)
case _ => throw new IllegalArgumentException("I only eat fish")
}
}
}
但我想为他们打字更好。
那么我可以在使用类型参数/泛型时保留 运行时间多态性吗?
我不确定这是否是最佳方法,但它似乎有效。您可以允许将任何种类的食物传递给动物冒着 class 抛出异常的风险,并在发生时进行处理。
class Food
abstract class Animal {
type SuitableFood <: Food
def eat(food: SuitableFood)
def eatWithExceptionHandling(food: Food) {
try {
eat(food.asInstanceOf[SuitableFood])
}
catch {
case ex: ClassCastException => println("Wrong food")
}
}
}
class Grass extends Food
class Fish extends Food
class Cow extends Animal {
type SuitableFood = Grass
override def eat(food: Grass) {
println("Cow eating grass")
}
}
class Cat extends Animal {
type SuitableFood = Fish
override def eat(food: Fish) {
println("Cat eating fish")
}
}
val (cow, cat, grass ,fish) = (new Cow, new Cat, new Grass, new Fish)
cow.eat(grass) //"Cow eating grass"
cat.eat(fish) //"Cat eating fish"
//cow.eat(fish) // error: type mismatch
cow.eatWithExceptionHandling(grass) //"Cow eating grass"
cow.eatWithExceptionHandling(fish) //"Wrong food"
Now that I have used abstract-type member (or type-parameter) , I lose the runtime polymorphism (at last line). (that using base type Animal to typing arbitrary subtypes and run with no problem.)
不,您可以用其子类型替换 Animal
(在这种情况下,并非总是如此!),但反之则不行。如果可以的话,您也可以使用 Object
,因为它也是 Cat
:
val object: Object = new Cat
object.eat(new Fish)
希望您明白为什么这不应该编译。
或者你可以换一种说法:应该
val animal: Animal = makeAnAnimal()
animal.eat(new Fish)
编译?如果您认为答案是 "yes",请考虑 makeAnAnimal()
可以 return 一个 Cow
。