协变关键字
本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 61 课,共 110 课。
在子类中重写方法时,Dart 通常要求参数类型完全匹配。但有时你希望子类方法接受比父类更具体的类型。covariant 关键字可以实现这一点。
考虑这样一种情况:Animal 类有一个接受另一个 Animal 的方法:
class Animal {
void chase(Animal other) {
print('Chasing an animal');
}
}
class Dog extends Animal {
@override
void chase(covariant Dog other) {
print('Dog chasing another dog');
}
}如果没有 covariant,Dart 会报错,因为 Dog 和 Animal 不是同一种类型。在参数前添加 covariant,就是在告诉 Dart:“我知道这个类型更具体,而且我会确保只传入正确的类型。”
当子类在逻辑上应该只与同类对象配合使用时,这很有用:
void main() {
Dog dog1 = Dog();
Dog dog2 = Dog();
dog1.chase(dog2); // 可以运行:Dog 追逐另一只狗
}不过要小心,使用 covariant 会将类型安全检查推迟到运行时。如果你通过父类引用使用错误的类型调用该方法,就会得到运行时错误,而不是编译时错误。只有在你确信传入的类型正确时才使用它。
挑战
简单让我们构建一个宠物兼容系统,使用 covariant 关键字,确保宠物只能和同类玩耍。你将创建一个宠物类层次结构,其中每种类型都有一个 playWith 方法,且只接受相同类型的宠物。
你将把代码分成两个文件:
pets.dart:在这里定义宠物类层次结构:- 一个
Pet类,包含一个String name属性和一个构造函数。添加一个playWith(Pet other)方法,输出[name] plays with [other.name] - 一个继承自
Pet的Cat类,并使用covariant关键字重写playWith,使其只接受Cat。它应输出[name] and [other.name] chase yarn together - 一个继承自
Pet的Dog类,并使用covariant关键字重写playWith,使其只接受Dog。它应输出[name] and [other.name] fetch the ball together - 一个继承自
Pet的Rabbit类,并使用covariant关键字重写playWith,使其只接受Rabbit。它应输出[name] and [other.name] hop around together
- 一个
main.dart:导入宠物文件,并演示每种宠物如何只和同类玩耍:- 创建两个名为
'Whiskers'和'Mittens'的Cat对象,然后让 Whiskers 和 Mittens 玩耍 - 创建两个名为
'Buddy'和'Max'的Dog对象,然后让 Buddy 和 Max 玩耍 - 创建两个名为
'Flopsy'和'Cotton'的Rabbit对象,然后让 Flopsy 和 Cotton 玩耍
- 创建两个名为
covariant 关键字允许每个子类将参数类型从 Pet 缩窄为自身的具体类型,确保同类宠物之间的交互具有类型安全性。
预期输出:
Whiskers and Mittens chase yarn together
Buddy and Max fetch the ball together
Flopsy and Cotton hop around together亲手试试
import 'pets.dart';
void main() {
// TODO: 创建两个 Cat 对象,分别命名为 'Whiskers' 和 'Mittens'
// 然后让 Whiskers 和 Mittens 一起玩
// TODO: 创建两个 Dog 对象,分别命名为 'Buddy' 和 'Max'
// 然后让 Buddy 和 Max 一起玩
// TODO: 创建两个 Rabbit 对象,分别命名为 'Flopsy' 和 'Cotton'
// 然后让 Flopsy 和 Cotton 一起玩
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Dart 在线编译器