Scala 类型 : Class A is not equal to the T where T is: type T = A

标签 scala types path-dependent-type

我正在阅读《Scala 编程》一书的第 20.7 节,我想知道为什么这段代码编译时:

class Food
class Fish extends Food
class Grass extends Food

abstract class Animal {
  type SuitableFood <: Food
  def eat(food: SuitableFood)
}


class Cow extends Animal {
  type SuitableFood = Grass
  override def eat(food: Grass) {}
}


val bessy: Animal = new Cow

bessy eat (new bessy.SuitableFood)

此代码没有(其余代码与之前相同,仅最后一行发生变化):

bessy eat (new Grass)

据我了解,Grass 的类型与 Cow.SuitableFood 相同。

另外,我对这个例子还有另一个问题:

如果 bessy 是 Animal 类型,编译器如何知道它需要合适的食物类型 -> Grass 而不是 Food 类型?因为尝试提供新的 Food 会出现类型不匹配的编译错误,但 Animal 类需要 Food 类型,并且 bessy 的类型已明确定义:Animal

最佳答案

这是因为 bessie 被声明为 Animal 而不是 Cowbessie.SuitableFood 是“路径相关类型”(见下文)。

试试这个:

val clarabelle: Cow = new Cow

clarabelle eat (new Grass)

这是有效的,因为编译器可以clarabelle 的声明类型推断出 clarabelle.SuitableFood = Grass

由于 bessie 被声明为 Animal,而不是 Cow,编译器无法安全地推断出 bessie.SuitableFood = Grass.* 当您说 new bessie.SuitableFood 时,编译器会生成代码来查看实际的 bessie 对象并生成适当类型的新实例。 bessie.SuitableFood 是“路径相关类型”:“path ”(bessie. 部分),它指向最后一个标识符 (SuitableFood) 实际上是类型的一部分。这使您能够为同一类的每个单独对象拥有类型的自定义版本。

<小时/>

*嗯,实际上,我认为如果编译器更聪明一点,它可以推断出 bessie.SuitableFood = Grass,因为 bessie 是一个val,而不是 var,因此不会更改其类型。换句话说,编译器应该知道,尽管 bessie 被声明为 Animal,但她实际上是一头 Cow。也许编译器的 future 版本将利用这些知识,也许有一个很好的理由为什么这不是一个好主意,比我更专家的人会告诉我们。 (后记:有人刚刚做到了!请参阅下面特拉维斯·布朗的评论。)

关于Scala 类型 : Class A is not equal to the T where T is: type T = A,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32161100/

相关文章:

javascript - 尝试从 Angular 6 中的输入访问值时,Event 和 event.target 的正确类型是什么?

c - 这个声明声明了什么?

scala - 路径依赖类型和嵌套特征

scala - 如何使用 Shapeless 为具有依赖类型的类型类创建实例

具有额外约束的 Scala 无形 KList

scala - 在Scala中方便地编写元组函数

scala - 使用 Scala 和 Spray.io 从 Future onComplete 案例中返回一个字符串

haskell - haskell如何得到 'downcast'类型接口(interface)?

Scala用var覆盖非抽象def

scala - 我可以在 where 或过滤器中有条件吗?