is および as 演算子
CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 60/110。
runtimeType は正確な型を返しますが、Dartは型チェックやキャストにおいてより実用的な2つの演算子、is と as を提供しています。
is 演算子は、オブジェクトが特定の型であるかどうかをチェックし、ブール値を返します。runtimeType とは異なり、親の型に対しても true を返します:
class Animal {}
class Dog extends Animal {}
void main() {
Animal pet = Dog();
print(pet is Dog); // true
print(pet is Animal); // true (DogはAnimalです)
print(pet is String); // false
}if 文の中で is を使用すると、Dart は自動的に型をプロモート(昇格)させ、明示的なキャストなしでサブクラスのメンバーにアクセスできるようになります。
void handleAnimal(Animal animal) {
if (animal is Dog) {
// ここでは Dart は animal が Dog であることを認識しています
animal.bark(); // Dog 特有のメソッドを呼び出すことができます
}
}as 演算子は、オブジェクトを特定の型に明示的にキャストします。型が確実である場合に使用します:
Animal pet = Dog();
Dog myDog = pet as Dog; // Dogにキャスト
myDog.bark();as には注意してください。キャストに失敗すると、例外がスローされます。そのため、is を型プロモーションと組み合わせる方が、as を直接使用するよりも多くの場合安全です。また、is! を使用して、オブジェクトが特定の型でないことを確認することもできます。
チャレンジ
簡単is 演算子と as 演算子を使用して、さまざまな図形タイプを識別し、操作する図形処理システムを構築しましょう。図形の階層を作成し、タイプをチェックしてタイプ固有のプロパティに安全にアクセスする関数を記述します。
コードを2つのファイルに整理します:
shapes.dart: ここで図形の階層を定義します:String nameプロパティとコンストラクタを持つShapeクラス。[name] is a shapeと出力するdescribe()メソッドを含めます。Shapeを継承し、追加のdouble radiusプロパティを持つCircleクラス。Circle with radius: [radius]と出力するgetCircleInfo()メソッドを追加します。Shapeを継承し、追加のdouble widthとdouble heightプロパティを持つRectangleクラス。Rectangle: [width] x [height]と出力するgetRectangleInfo()メソッドを追加します。
main.dart: 図形ファイルをインポートし、以下の処理を行う関数processShape(Shape shape)を作成します:- 最初に図形に対して
describe()を呼び出します。 isを使用して図形がCircleかどうかをチェックします。もしそうなら、型プロモーション(type promotion)を使用してgetCircleInfo()を呼び出します。isを使用して図形がRectangleかどうかをチェックします。もしそうなら、as演算子を使用してキャストし、getRectangleInfo()を呼び出します。is!を使用して図形がCircleではなく、かつRectangleでもないことをチェックします。もしそうなら、Unknown shape typeと出力します。
main()関数内で以下を行います:- 名前が
'Round'で半径が5.0のCircleを作成し、processShape()に渡します。 - 空行を出力します。
- 名前が
'Box'で幅が4.0、高さが3.0のRectangleを作成し、processShape()に渡します。 - 空行を出力します。
- 名前が
'Mystery'のベースとなるShapeを作成し、processShape()に渡します。
- 最初に図形に対して
このチャレンジでは、Circle に対する自動型プロモーションを伴う is の使用と、Rectangle に対する明示的なキャストを伴う as の使用の両方のアプローチを示します。また、is! が特定のサブタイプに一致しない図形を特定するのにどのように役立つかも確認できます。
期待される出力:
Round is a shape
Circle with radius: 5.0
Box is a shape
Rectangle: 4.0 x 3.0
Mystery is a shape
Unknown shape typeチートシート
is 演算子は、オブジェクトが特定の型であるかどうかをチェックし、ブール値を返します。また、親の型に対しても true を返します:
class Animal {}
class Dog extends Animal {}
void main() {
Animal pet = Dog();
print(pet is Dog); // true
print(pet is Animal); // true (Dog は Animal です)
print(pet is String); // false
}if 文の中で is を使用すると、Dart は自動的に型を昇格(プロモート)させ、明示的なキャストなしでサブクラスのメンバーにアクセスできるようになります:
void handleAnimal(Animal animal) {
if (animal is Dog) {
// ここで Dart は animal が Dog であることを認識します
animal.bark(); // Dog 特有のメソッドを呼び出すことができます
}
}as 演算子は、オブジェクトを特定の型に明示的にキャストします:
Animal pet = Dog();
Dog myDog = pet as Dog; // Dog にキャスト
myDog.bark();as を使用する際は注意してください。キャストに失敗すると、例外がスローされます。is と型プロモーションを組み合わせる方が、as を直接使用するよりも安全な場合が多いです。
オブジェクトが特定の型でないことを確認するには、is! を使用します:
if (animal is! Dog) {
print("Not a dog");
}自分で試してみよう
import 'shapes.dart';
// TODO: 以下の処理を行う関数 processShape(Shape shape) を作成してください:
// 1. 最初に shape に対して describe() を呼び出す
// 2. 'is' を使って shape が Circle かどうかを確認する。そうであれば、型プロモーション(type promotion)を使用して getCircleInfo() を呼び出す
// 3. 'is' を使って shape が Rectangle かどうかを確認する。そうであれば、'as' 演算子を使ってキャストし、getRectangleInfo() を呼び出す
// 4. 'is!' を使って shape が Circle でも Rectangle でもないことを確認する。その場合は、"Unknown shape type" とプリントする
void main() {
// TODO: 半径 5.0 の 'Round' という名前の Circle を作成し、それを processShape() に渡す
// TODO: 空行をプリントする
// TODO: 幅 4.0、高さ 3.0 の 'Box' という名前の Rectangle を作成し、それを processShape() に渡す
// TODO: 空行をプリントする
// TODO: 'Mystery' という名前のベースとなる Shape を作成し、それを processShape() に渡す
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4Null Safety
Null Safety 入門Nullable と Non-Nullable? 演算子と ! 演算子late キーワードと Null SafetyNull-Aware 演算子クラスにおける Null Safetyまとめ:ユーザープロフィールシステム10コレクションとジェネリクス
List, Set, Map の概要型安全なコレクションジェネリッククラスジェネリックメソッドジェネリクスの制約Iterable と Iteratorまとめ:ジェネリックなストレージ