颤振中协变的功能

functioning of covariant in flutter

提问人:Manishyadav 提问时间:2/23/2022 更新时间:5/26/2023 访问量:6717

问:

我正在浏览 dart 文档,在那里我遇到了这个代码和这个术语。我浏览了一些文档,但我不明白它是什么。详细解释的答案总是值得赞赏的。covariantfunction

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

class Mouse extends Animal { ... }

class Cat extends Animal {
  @override
  void chase(covariant Mouse x) { ... }
}
颤振 飞镖

评论


答:

0赞 Abhishek Doshi 2/23/2022 #1

通过使用协变关键字,您可以禁用类型检查,并负责确保您在实践中不违反合同。

正如您在示例中看到的,如果要重写一个方法,则其参数也应该相同。但是,如果您使用协变,它将允许您使用鼠标而不是动物。

评论

2赞 TSR 2/23/2022
不,从技术上讲,您不会禁用类型检查,您是在告诉 dart 这个参数可以是 Mouse,禁用类型检查意味着允许任何参数,例如布尔值、字符串或数字
0赞 rjh 10/18/2022
类型检查也仍在进行 - 如果可能的话,在编译时,否则在运行时。
14赞 TSR 2/23/2022 #2

只要试着去掉关键词协变,它就会变得不言自明。

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

但是,Mouse 是 Animal 的子类型,因此如果您想允许这种情况而不会出错,请添加协变关键字

以前 enter image description here

enter image description here

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

46赞 rjh 9/19/2022 #3

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

由于在您的示例中接受 的参数,因此您必须在重写中执行相同的操作:Animal.chaseAnimal

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

为什么?想象一下,如果没有这样的限制。 可以定义 while 可以 定义。然后想象一下你有一个,你打电话 其中之一。如果动物是狗,它会起作用,但如果动物是猫,猫就不是老鼠!猫 班级没有办法处理被要求追逐另一只猫。Catvoid chase(Mouse x)Dogvoid chase(Cat x)List<Animal> animalschase(cat)

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

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

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

  1. 允许您省略检查,因为它是为您完成的。x is Mouse
  2. 如果任何 Dart 代码调用其中 x 不是 Mouse 或其子类(如果在编译时已知),则创建编译时错误。Cat.chase(x)
  3. 在其他情况下创建运行时错误。

另一个例子是关于对象的方法。假设你有一个班级: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 与不是 Points 的事物进行比较是没有意义的。Point(1,2) == "string"

你可以用它来告诉 Dart 这应该是一个点,否则它就是一个错误。这也可以让您放下零件:covariantotherother is Point

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

为什么叫“协变”?

协变是一个花哨的类型理论术语,但它基本上意味着“这个类或其子类”。换句话说,它意味着类型 在类型层次结构中等于或更低。

你明确地告诉 Dart 将这个参数的类型检查收紧到原始参数的子类。 第一个例子:将动物收紧到老鼠身上;第二种:收紧 Object to Point。

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

有关更多信息,此 Stack Overflow 问题是一个很好的资源。

评论

0赞 Alex 8/22/2023
“猫课没办法处理被要求追另一只猫”我看到猫一直在追猫:))
0赞 Ramesh-X 5/26/2023 #4

协变是一个关键字,它允许您使用新类型的参数(原始类型的子类)覆盖方法。当您希望在不破坏与超类函数的兼容性的情况下为不同类型的参数提供更精确的行为时,这很方便。

class A {}

class B extends A {
}

class C extends B {
}

class D extends A {}

这些是一些简单的类,我将用它们来演示不同类型的参数。

// Create a class with a method
class P {
  void method(B b) {}
}

// You can create another class and override the 
// method without changing the type of the parameter.
class Q extends P {
  @override
  void method(B b) {}
}

// Without any problem, you can override 
// the method to take a superclass as an argument.
class R extends P {
  @override
  void method(A a) {}
}

// But if you override to take a subclass
// it gives an error.
class S extends P {
  @override
  void method(C c) {}  // Error
}

// You can avoid this error by 
// adding the `covariant` keyword.
class T extends P {
  @override
  void method(covariant C c) {}
}

// You can even add `covariant` with
// a superclass of the original type.
class U extends P {
  @override
  void method(covariant A a) {}
}

// But you can't use this to override
// methods to take arguments with unrelated types. 
// (Not in the hierarchy of the original type)
class V extends P {
  @override
  void method(covariant D d) {}  // Error
}