了解 Scala 对抽象类型的使用 类
Understanding Scala use of abstract types and Classes
下一个代码无法编译。为什么Santorin
不能吃HorseFood
? Tornado
被声明为新的 Horse
,Horse
是 Animal
的子类型,但它可以 "eat" HorseFood
.
import scala.io.StdIn._
import util._
class Food
abstract class Animal
{
type SuitableFood <: Food
def eat(food: SuitableFood)
}
class Grass extends Food /*extends meaning should be "more specific than*/
class Fish extends Food
class HorseFood extends Grass
class Cow extends Animal
{
type SuitableFood = Grass
override def eat(food: SuitableFood) = {}
}
class Horse extends Animal
{
type SuitableFood = Grass
override def eat(food: SuitableFood) = {}
}
class Whale extends Animal
{
type SuitableFood = Fish
override def eat(food: SuitableFood) = {}
}
object abstractExample1 {
def main(args: Array[String]) {
val bessy: Animal = new Cow
println("bessy = " + bessy)
bessy eat (new Grass).asInstanceOf[bessy.SuitableFood]
/*added this line because of a great answer someone posted for this questions but he deleted*/
val willie: Animal = new Whale
println("willie = " + willie)
val santorin: Animal = new Horse
println("santorin = " + santorin)
val tornado = new Horse
tornado eat new HorseFood
print("tornado = " + tornado)
santorin.eat(new HorseFood)
}
}
这难道不应该被自动允许吗(因为 Horse
扩展了 Animal
)?为什么不是?
请注意 Tornado
,正如所声明的那样,可以吃 HorseFood
扩展 Grass
,并且 class Horse
处的食物参数是 Grass
.
=
有问题吗?我的意思是,SuitableFood
正好是 Grass
而不是 Grass
.
的 class C
扩展
Animal#SuitableFood
是 Food
的子类型
implicitly[Animal#SuitableFood <:< Food]
分配给 Animal
类型 val
的每个 Horse
实例都包含全新的 SuitableFood
类型,它是 Animal#SuitableFood
的子类型
val santorin: Animal = new Horse
val santorin2: Animal = new Horse
implicitly[santorin.SuitableFood <:< Animal#SuitableFood]
implicitly[santorin2.SuitableFood <:< Animal#SuitableFood]
implicitly[santorin.SuitableFood =:= santorin2.SuitableFood] //-- fails
// ^^^^^^^ ^^^^^^^
// these types are different
implicitly[santorin.SuitableFood =:= Grass] // -- fails
val tornado = new Horse
val tornado2 = new Horse
implicitly[tornado.SuitableFood =:= tornado2.SuitableFood] // compiles!
// ^^^^^^^ ^^^^^^^
// Grass =:= Grass
implicitly[tornado.SuitableFood =:= Grass] // compiles
santorin: Animal
的 eat
方法签名如下:
def eat(food: santorin.SuitableFood) // SuitableFood is path-dependent
santorin.SuitableFood
是 Food
和 Animal#SuitableFood
的子类型
HorseFood
是 Food
和 Grass
的子类型,但不是 santorin.SuitableFood
或 Animal#SuitableFood
的子类型
implicitly[HorseFood <:< Food]
implicitly[HorseFood <:< Grass]
implicitly[HorseFood <:< santorin.SuitableFood]// -- fails
implicitly[HorseFood <:< Animal#SuitableFood]// -- fails
这就是在 HorseFood
上调用方法 eat
也失败的原因。因为 HorseFood
不是 santorin.SuitableFood
.
的子类型
这就是以下工作的原因:
santorin.eat((new HorseFood).asInstanceOf[santorin.SuitableFood])
您应该阅读有关 variance 的内容。
你的类是不变的。这意味着 Animal
with SuitableFood <: Food
不能是 Animal
with SuitableFood = HorseFood
.
把你的类改写成generic-like风格就可以看到了:
trait Food
class Grass extends Food
class HorseFood extends Grass
abstract class Animal[SuitableFood <: Food] {
def eat(food: SuitableFood)
}
val animal1: Animal[HorseFood] = null
//the next line doesn't compile because Animal[HorseFood] isn't a subclass of Animal[Food]
val animal2: Animal[Food] = animal1
所以能吃的动物Food
不能吃HorseFood
。
Santorin 是 Animal
而非 Horse
,因此它 'eats' 'type' 而非 HorseFood
。这是因为对它的引用是为了 Animal
。
更改 val santorin: Animal = new Horse
至 val santorin: Horse = new Horse
它会很好
下一个代码无法编译。为什么Santorin
不能吃HorseFood
? Tornado
被声明为新的 Horse
,Horse
是 Animal
的子类型,但它可以 "eat" HorseFood
.
import scala.io.StdIn._
import util._
class Food
abstract class Animal
{
type SuitableFood <: Food
def eat(food: SuitableFood)
}
class Grass extends Food /*extends meaning should be "more specific than*/
class Fish extends Food
class HorseFood extends Grass
class Cow extends Animal
{
type SuitableFood = Grass
override def eat(food: SuitableFood) = {}
}
class Horse extends Animal
{
type SuitableFood = Grass
override def eat(food: SuitableFood) = {}
}
class Whale extends Animal
{
type SuitableFood = Fish
override def eat(food: SuitableFood) = {}
}
object abstractExample1 {
def main(args: Array[String]) {
val bessy: Animal = new Cow
println("bessy = " + bessy)
bessy eat (new Grass).asInstanceOf[bessy.SuitableFood]
/*added this line because of a great answer someone posted for this questions but he deleted*/
val willie: Animal = new Whale
println("willie = " + willie)
val santorin: Animal = new Horse
println("santorin = " + santorin)
val tornado = new Horse
tornado eat new HorseFood
print("tornado = " + tornado)
santorin.eat(new HorseFood)
}
}
这难道不应该被自动允许吗(因为 Horse
扩展了 Animal
)?为什么不是?
请注意 Tornado
,正如所声明的那样,可以吃 HorseFood
扩展 Grass
,并且 class Horse
处的食物参数是 Grass
.
=
有问题吗?我的意思是,SuitableFood
正好是 Grass
而不是 Grass
.
C
扩展
Animal#SuitableFood
是 Food
implicitly[Animal#SuitableFood <:< Food]
分配给 Animal
类型 val
的每个 Horse
实例都包含全新的 SuitableFood
类型,它是 Animal#SuitableFood
val santorin: Animal = new Horse
val santorin2: Animal = new Horse
implicitly[santorin.SuitableFood <:< Animal#SuitableFood]
implicitly[santorin2.SuitableFood <:< Animal#SuitableFood]
implicitly[santorin.SuitableFood =:= santorin2.SuitableFood] //-- fails
// ^^^^^^^ ^^^^^^^
// these types are different
implicitly[santorin.SuitableFood =:= Grass] // -- fails
val tornado = new Horse
val tornado2 = new Horse
implicitly[tornado.SuitableFood =:= tornado2.SuitableFood] // compiles!
// ^^^^^^^ ^^^^^^^
// Grass =:= Grass
implicitly[tornado.SuitableFood =:= Grass] // compiles
santorin: Animal
的 eat
方法签名如下:
def eat(food: santorin.SuitableFood) // SuitableFood is path-dependent
santorin.SuitableFood
是 Food
和 Animal#SuitableFood
HorseFood
是 Food
和 Grass
的子类型,但不是 santorin.SuitableFood
或 Animal#SuitableFood
implicitly[HorseFood <:< Food]
implicitly[HorseFood <:< Grass]
implicitly[HorseFood <:< santorin.SuitableFood]// -- fails
implicitly[HorseFood <:< Animal#SuitableFood]// -- fails
这就是在 HorseFood
上调用方法 eat
也失败的原因。因为 HorseFood
不是 santorin.SuitableFood
.
这就是以下工作的原因:
santorin.eat((new HorseFood).asInstanceOf[santorin.SuitableFood])
您应该阅读有关 variance 的内容。
你的类是不变的。这意味着 Animal
with SuitableFood <: Food
不能是 Animal
with SuitableFood = HorseFood
.
把你的类改写成generic-like风格就可以看到了:
trait Food
class Grass extends Food
class HorseFood extends Grass
abstract class Animal[SuitableFood <: Food] {
def eat(food: SuitableFood)
}
val animal1: Animal[HorseFood] = null
//the next line doesn't compile because Animal[HorseFood] isn't a subclass of Animal[Food]
val animal2: Animal[Food] = animal1
所以能吃的动物Food
不能吃HorseFood
。
Santorin 是 Animal
而非 Horse
,因此它 'eats' 'type' 而非 HorseFood
。这是因为对它的引用是为了 Animal
。
更改 val santorin: Animal = new Horse
至 val santorin: Horse = new Horse
它会很好