我在浏览dart文档时,偶然发现了这个代码和术语covariant
。我浏览了一些文档,但没有弄清楚它的function
是什么。如果能提供详细的解释,我将不胜感激。
class Animal {
void chase(Animal x) { ... }
}
class Mouse extends Animal { ... }
class Cat extends Animal {
@override
void chase(covariant Mouse x) { ... }
}
3条答案
按热度按时间whhtz7ly1#
在Dart中,如果你覆盖了一个超类方法,覆盖方法的参数必须与原始方法具有相同的类型。
由于示例中的
Animal.chase
接受Animal
的参数,因此您必须在重写中执行相同的操作:为什么?想象一下如果没有这样的限制。
Cat
可以定义void chase(Mouse x)
,而Dog
可以定义void chase(Cat x)
。然后想象一下你有一个List<Animal> animals
,你在其中一个上调用chase(cat)
。如果动物是狗,它会工作,但如果动物是猫,Cat不是老鼠!Cat类没有办法处理被要求追逐另一只猫。所以你必须使用
void chase(Animal x)
。我们可以通过添加运行时类型检查来模拟void chase(Mouse x)
类型签名:事实证明,这是一个相当常见的操作,如果可以在编译时检查它就更好了。所以Dart添加了一个
covariant
操作符。将函数签名更改为chase(covariant Mouse x)
(其中Mouse是Animal的子类)做了三件事:1.允许您省略
x is Mouse
检查,因为它已为您完成。1.如果任何Dart代码调用
Cat.chase(x)
,其中x不是Mouse或其子类(如果在编译时已知),则创建编译时错误。1.在其他情况下创建运行时错误。
另一个例子是对象上的
operator ==(Object x)
方法。假设你有一个类Point
:你可以这样实现
operator==
:但是即使你比较
Point(1,2) == "string"
或者一个数字或者其他对象,这段代码也能编译。你可以使用
covariant
来告诉Dartother
应该是一个Point,否则它是一个错误。这也允许你删除other is Point
部分:为什么称之为“协变量”?
协变是类型理论中的一个花哨的术语,但它基本上意味着“这个类或它的子类”。换句话说,它意味着在类型层次结构中相等或更低的类型。
你明确地告诉Dart把这个参数的类型检查严格到原始参数的一个 * 子类 *。对于第一个例子:将动物紧固到小鼠;对于第二个:将对象拧紧到点。
有用的相关术语是逆变,这意味着类型层次结构中的类型相等或更高,以及不变,这意味着正是这种类型。
有关更多信息,this Stack Overflow question是一个很好的资源。
j13ufse22#
只要试着去掉关键词协变,它就会变得不言自明。
您将收到一个编译器错误,指出您正在覆盖参数类型不匹配的方法
Expected: Animal, Actual: Mouse
但是,Mouse是Animal的子类型,因此如果您希望允许这种情况而不出错,请添加covariant关键字
之前
之后
这里你可以看到老鼠是动物的一个亚型
pbossiut3#
通过使用covariant关键字,您可以禁用类型检查,并负责确保您在实践中不违反契约。
正如你在例子中看到的,如果你重写一个方法,它的参数也应该是相同的。但是如果你使用协变,它将允许你使用Mouse而不是Animal。