Flutter协变函数

f0brbegy  于 2023-04-07  发布在  Flutter
关注(0)|答案(3)|浏览(152)

我在浏览dart文档时,偶然发现了这个代码和术语covariant。我浏览了一些文档,但没有弄清楚它的function是什么。如果能提供详细的解释,我将不胜感激。

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

class Mouse extends Animal { ... }

class Cat extends Animal {
  @override
  void chase(covariant Mouse x) { ... }
}
whhtz7ly

whhtz7ly1#

在Dart中,如果你覆盖了一个超类方法,覆盖方法的参数必须与原始方法具有相同的类型。
由于示例中的Animal.chase接受Animal的参数,因此您必须在重写中执行相同的操作:

class Cat extends Animal {
  @override
  void chase(Animal x) { ... }
}

为什么?想象一下如果没有这样的限制。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)类型签名:

void chase(Animal x) {
  if (x is Mouse) {
    /* do chase */
  } else {
    /* throw error */
  }
}

事实证明,这是一个相当常见的操作,如果可以在编译时检查它就更好了。所以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==

class Point {
  final int x, y;
  Point(this.x, this.y);

  bool operator==(Object other) {
    if (other is Point) {
      return x == other.x && y == other.y;
    } else {
      return false;
    }
  }
}

但是即使你比较Point(1,2) == "string"或者一个数字或者其他对象,这段代码也能编译。
你可以使用covariant来告诉Dart other应该是一个Point,否则它是一个错误。这也允许你删除other is Point部分:

bool operator==(covariant Point other) =>
  x == other.x && y == other.y;

为什么称之为“协变量”?

协变是类型理论中的一个花哨的术语,但它基本上意味着“这个类或它的子类”。换句话说,它意味着在类型层次结构中相等或更低的类型。
你明确地告诉Dart把这个参数的类型检查严格到原始参数的一个 * 子类 *。对于第一个例子:将动物紧固到小鼠;对于第二个:将对象拧紧到点。
有用的相关术语是逆变,这意味着类型层次结构中的类型相等或更高,以及不变,这意味着正是这种类型。
有关更多信息,this Stack Overflow question是一个很好的资源。

j13ufse2

j13ufse22#

只要试着去掉关键词协变,它就会变得不言自明。
您将收到一个编译器错误,指出您正在覆盖参数类型不匹配的方法Expected: Animal, Actual: Mouse
但是,Mouse是Animal的子类型,因此如果您希望允许这种情况而不出错,请添加covariant关键字

之前

之后

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

pbossiut

pbossiut3#

通过使用covariant关键字,您可以禁用类型检查,并负责确保您在实践中不违反契约。
正如你在例子中看到的,如果你重写一个方法,它的参数也应该是相同的。但是如果你使用协变,它将允许你使用Mouse而不是Animal。

相关问题