Menu
Coddy logo textTech

is および as 演算子

CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 60/110。

runtimeType は正確な型を返しますが、Dartは型チェックやキャストにおいてより実用的な2つの演算子、isas を提供しています。

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! を使用して、オブジェクトが特定の型でないことを確認することもできます。

challenge icon

チャレンジ

簡単

is 演算子と as 演算子を使用して、さまざまな図形タイプを識別し、操作する図形処理システムを構築しましょう。図形の階層を作成し、タイプをチェックしてタイプ固有のプロパティに安全にアクセスする関数を記述します。

コードを2つのファイルに整理します:

  • shapes.dart: ここで図形の階層を定義します:
    • String name プロパティとコンストラクタを持つ Shape クラス。[name] is a shape と出力する describe() メソッドを含めます。
    • Shape を継承し、追加の double radius プロパティを持つ Circle クラス。Circle with radius: [radius] と出力する getCircleInfo() メソッドを追加します。
    • Shape を継承し、追加の double widthdouble 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.0Circle を作成し、processShape() に渡します。
    • 空行を出力します。
    • 名前が 'Box' で幅が 4.0、高さが 3.0Rectangle を作成し、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() に渡す
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン