协变在颤振中的作用

Man*_*dav 24 class dart flutter

我正在浏览 dart 文档,在那里我遇到了这段代码和这个术语 covariant。我浏览了一些文档,但我不明白function其中的内容。详细解释的答案总是值得赞赏的。

class Animal {
  void chase(Animal x) { ... }
}

class Mouse extends Animal { ... }

class Cat extends Animal {
  @override
  void chase(covariant Mouse x) { ... }
}
Run Code Online (Sandbox Code Playgroud)

rjh*_*rjh 55

在 Dart 中,如果重写超类方法,则重写方法的参数必须具有与原始方法相同的类型。

\n

因为Animal.chase在你的例子中接受一个参数Animal,因此您必须在覆盖中执行相同的操作:

\n
class Cat extends Animal {\n  @override\n  void chase(Animal x) { ... }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

为什么?想象一下,如果没有这样的限制。Cat可以定义void chase(Mouse x)同时Dog可以\n定义void chase(Cat x)。然后想象你有一个List<Animal> animals并且你打电话chase(cat)他们中的任何一个。如果动物是狗,它会起作用,但如果动物是猫,猫就不是老鼠!Cat\n类无法处理被要求追逐另一只 Cat 的情况。

\n

所以你被迫使用void chase(Animal x). 我们可以模拟一个void chase(Mouse x)通过添加运行时类型检查来模拟类型签名:

\n
void chase(Animal x) {\n  if (x is Mouse) {\n    /* do chase */\n  } else {\n    /* throw error */\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

事实证明这是一个相当常见的操作,如果可以在编译时检查它会更好\n如果可能的话。所以Dart添加了一个covariant运算符。将函数签名更改为chase(covariant Mouse x)\n(其中 Mouse 是 Animal 的子类)会执行三件事:

\n
    \n
  1. 允许您省略x is Mouse,因为它已为您完成。
  2. \n
  3. 如果任何 Dart 代码调用,则会产生编译时错误Cat.chase(x)如果任何 Dart 代码调用 x 不是 Mouse 或其子类 \xe2\x80\x94(如果在编译时已知),则会
  4. \n
  5. 在其他情况下会产生运行时错误。
  6. \n
\n
\n

另一个例子是operator ==(Object x)对象上的方法。假设你有课Point

\n

你可以实施operator==这样实现:

\n
class Point {\n  final int x, y;\n  Point(this.x, this.y);\n\n  bool operator==(Object other) {\n    if (other is Point) {\n      return x == other.x && y == other.y;\n    } else {\n      return false;\n    }\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

但即使你比较这段代码也能编译Point(1,2) == "string"数字或其他对象,此代码也会编译。将点与非点的事物进行比较是没有意义的。

\n

你可以用来covariant告诉 Dart 这other应该是一个 Point,否则会出错。这可以让你放弃other is Point部分:

\n
bool operator==(covariant Point other) =>\n  x == other.x && y == other.y;\n
Run Code Online (Sandbox Code Playgroud)\n
\n

为什么称为“协变”?

\n

协变是一个奇特的类型理论术语,但它基本上意味着“这个类或其子类”。换句话说,这意味着类型层次结构中相同或较低的类型。

\n

您明确告诉 Dart 加强对此参数对子类的类型检查原始参数的第二个:将对象收紧到点。

\n

有用的相关术语是contravariant,这意味着类型层次结构中等于或更高的类型,以及invariant,\n这意味着正是这种类型。

\n

要了解更多信息,这个 Stack Overflow 问题是一个很好的资源。

\n


TSR*_*TSR 14

只要尝试删除关键字协变,它就会变得不言自明。

您将收到一个编译器错误,表明您正在覆盖参数类型不匹配的方法Expected: Animal, Actual: Mouse

但是,Mouse 是 Animal 的子类型,因此如果您希望允许这种情况而不发生错误,请添加 covariant 关键字

在此输入图像描述

在此输入图像描述

在这里你可以看到老鼠是动物的亚型