covariant キーワード
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); // 成功:犬が別の犬を追いかける
}ただし、注意が必要です。covariant を使用すると、型の安全性が実行時(ランタイム)へと移行します。親クラスの参照を介して誤った型でメソッドを呼び出すと、コンパイル時エラーではなく実行時エラーが発生します。渡される型に確信がある場合に使用してください。
チャレンジ
簡単covariant キーワードを使用して、ペットが同じ種類のペットとしか遊べないようにするペット互換性システムを構築しましょう。各タイプが同じタイプのペットのみを受け入れる playWith メソッドを持つ、ペットの階層構造を作成します。
コードを2つのファイルに整理します:
pets.dart: ここでペットの階層を定義します:String nameプロパティとコンストラクタを持つPetクラス。[name] plays with [other.name]と出力するplayWith(Pet other)メソッドを含めます。Petを継承し、covariantキーワードを使用してCatのみを受け入れるようにplayWithをオーバーライドするCatクラス。[name] and [other.name] chase yarn togetherと出力する必要があります。Petを継承し、covariantキーワードを使用してDogのみを受け入れるようにplayWithをオーバーライドするDogクラス。[name] and [other.name] fetch the ball togetherと出力する必要があります。Petを継承し、covariantキーワードを使用してRabbitのみを受け入れるようにplayWithをオーバーライドするRabbitクラス。[name] and [other.name] hop around togetherと出力する必要があります。
main.dart: ペットのファイルをインポートし、各ペットのタイプが自分の種類とだけ遊ぶ様子を示します:'Whiskers'と'Mittens'という名前の2つのCatオブジェクトを作成し、Whiskers を Mittens と遊ばせます。'Buddy'と'Max'という名前の2つのDogオブジェクトを作成し、Buddy を Max と遊ばせます。'Flopsy'と'Cotton'という名前の2つのRabbitオブジェクトを作成し、Flopsy を Cotton と遊ばせます。
covariant キーワードを使用すると、各サブクラスでパラメータの型を Pet から特定の型に絞り込むことができ、同じ種類のペット間での型安全な相互作用が保証されます。
期待される出力:
Whiskers and Mittens chase yarn together
Buddy and Max fetch the ball together
Flopsy and Cotton hop around togetherチートシート
covariantキーワードを使用すると、サブクラスは親クラスよりも具体的なパラメータ型でメソッドをオーバーライドできます。
covariantがない場合、Dartではメソッドをオーバーライドする際にパラメータ型が完全に一致する必要があります。covariantを使用すると、サブクラスでパラメータ型を絞り込むことができます:
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');
}
}これは、サブクラスが自身の型のみを扱う必要がある場合に便利です:
void main() {
Dog dog1 = Dog();
Dog dog2 = Dog();
dog1.chase(dog2); // Works: Dog chasing another dog
}重要: covariantを使用すると、型安全性がコンパイル時から実行時に移行します。親クラスの参照を介して間違った型でメソッドを呼び出すと、コンパイルエラーではなく実行時エラーが発生します。
自分で試してみよう
import 'pets.dart';
void main() {
// TODO: 'Whiskers' と 'Mittens' という名前の 2 つの Cat オブジェクトを作成します
// 次に Whiskers を Mittens と遊ばせます
// TODO: 'Buddy' と 'Max' という名前の 2 つの Dog オブジェクトを作成します
// 次に Buddy を Max と遊ばせます
// TODO: 'Flopsy' と 'Cotton' という名前の 2 つの Rabbit オブジェクトを作成します
// 次に Flopsy を Cotton と遊ばせます
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4Null Safety
Null Safety 入門Nullable と Non-Nullable? 演算子と ! 演算子late キーワードと Null SafetyNull-Aware 演算子クラスにおける Null Safetyまとめ:ユーザープロフィールシステム10コレクションとジェネリクス
List, Set, Map の概要型安全なコレクションジェネリッククラスジェネリックメソッドジェネリクスの制約Iterable と Iteratorまとめ:ジェネリックなストレージ