Dart 型判定演算子

3種の演算子一覧(as /is/is!)

演算子機能説明
as型強制キャスト;ライブラリのプレフィックス別名指定にも利用
is型判定:オブジェクトが指定型に該当する場合 true を返す
is!型判定:オブジェクトが指定型に該当しない場合 true を返す

obj is T の判定が成立する条件:オブジェクト obj が型 T を実装・継承していること(親クラス、インターフェース、Nullable型を含む)。

例:任意のオブジェクト is Object? は常に true となる。

is 演算子

安全な型判定

オブジェクトの実行時型を判定;判定結果がtrueの場合、コードブロック内で手動キャストなしでその型として直接利用可能。オブジェクトが null または型不一致の場合はfalseを返し、例外は発生しない。

以下でクラスオブジェクトを使用する例を記載する。クラスの学習がまだ済んでいない読者は、データを作成するための雛形と捉えて差し支えない。

class Person {
  String firstName = '';
}

class Employee extends Person {}

void main() {
  dynamic employee = Employee();

  // isによる型判定
  if (employee is Person) {
    // 分岐内に入るとemployeeは自動的にPerson型と認識される
    employee.firstName = "Jack";
    print(employee.firstName); // Jack が出力される
  }

  dynamic emptyObj = null;
  if (emptyObj is Person) {
    // nullはPersonに一致しないため実行されない
    print("一致しました");
  }
}Code language: Dart (dart)

上記コードではPersonクラスを定義し、それを継承したEmployeeクラスを作成しています。

コード内でisを用いてオブジェクトがPerson型か判定し、trueの場合は{}のコードブロック内でPerson型として直接扱えます。dynamic employee = Employee(); で動的型を使用しているためです。

2つ目の例 dynamic emptyObj = null; では値がnullのため emptyObj is Person はfalseとなり、{}内のコードは実行されません。

is! 演算子

逆の型判定

構文:

変数 is! 型

実質的に先述のisの結果を否定したものと同じ意味です。

!(変数 is 型) と等価で、オブジェクトが対象型ではないことを判定します。

例を見てみましょう:

class Person {
  String name = '';
}

void main() {
  dynamic obj = "テキスト";
  if (obj is! Person) {
    print("obj は Person 型ではありません");
  }
}Code language: Dart (dart)

上記例では{}内のコードが実行され「obj は Person 型ではありません」と出力されます。objはPersonの雛形から生成されたインスタンスではないためです。

as 演算子

型強制キャスト

使用方法:

(変数 as 対象型).プロパティ/メソッドCode language: JavaScript (javascript)

対象オブジェクトが確実に目標型であると100%確信できる場合のみ使用してください。そうでない場合実行時例外がスローされます。プログラムの堅牢性の観点から、多用は推奨されません。

class Teacher {
  String name = '';
}

void main() {
  dynamic jason = Teacher();
  // Teacher型に強制キャストしてプロパティにアクセス
  (jason as Teacher).name = "Jason";
  print((jason as Teacher).name); // Jason
}Code language: Dart (dart)

上記例の出力はJasonとなります

dynamic jason = Teacher(); でTeacherインスタンスを作成しているため、確実にTeacher型であると保証でき、この記述でエラーは発生しません。

下記のように記述するとエラーが発生します。

class Teacher {
  String name = '';
}

class Car {
  String name = '';
}

void main() {
  dynamic jason = Teacher();
  
  // Car型に強制キャストしてプロパティにアクセス
  (jason as Car).name = "Jason";//❌エラー
  print((jason as Car).name); //❌エラー
}Code language: Dart (dart)

jasonは元々Teacher型のインスタンスなのにCar型に強制キャストしているためエラーとなります。

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Unhandled exception:
type 'Teacher' is not a subtype of type 'Car' in type cast
#0      main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:12:10)
#1      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#2      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Code language: PHP (php)

asis 核心比較

// 記述1:asによる強制キャスト
(employee as Person).firstName = 'Bob';

// 記述2:isで事前判定してから利用
if (employee is Person) {
  employee.firstName = 'Bob';
}Code language: JavaScript (javascript)

employeenull または Person 型ではない場合の動作:

  • as を使用した記述:CastError が発生しプログラムが異常終了;
  • is を使用した記述:if分岐に入らず、コードにエラーは発生せず何も実行されない。

記述量は少し増えますがプログラムの堅牢性が高いため、優先してisによる判定方式を利用しましょう。

as の2つ目の用途

as の2つ目の用途

as は型キャスト以外に、ライブラリ読み込み時にライブラリに別名を付ける用途にも使えます

import 'dart:math' as math;

void main() {
  // ライブラリ別名経由でクラス・メソッドを呼び出す
  print(math.pi); // 3.141592653589793 が出力
}Code language: JavaScript (javascript)

最後に完全なサンプルコード

class Animal {}
class Cat extends Animal {}

void main() {
  dynamic obj = Cat();

  // 1. is による判定
  if (obj is Animal) {
    print("obj は Animal 型です");
  }

  // 2. is! による逆判定
  if (obj is! String) {
    print("obj は文字列ではありません");
  }

  // 3. as による強制キャスト
  Animal a = obj as Animal;

  // エラー例:実行時クラッシュする
  dynamic str = "hello";
  // Animal error = str as Animal; // CastError 発生
}Code language: JavaScript (javascript)

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です