0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Dart】Dynamic型とObject型について

Posted at

Dynamic型とObject型について調べてみた。

Dartのdynamic型は、コンパイル時に型チェックが行われないため、実行時エラーのリスクが高まる点で注意が必要。

代わりにObject型を使用することで、より安全なコードを書くことができる。

下記コードを例にする

void main() {
  // 動作確認用 dynamic 型
  dynamic valueDynamic = 'Hello, Dynamic!';
  print("dynamic型の初期値: $valueDynamic");
  valueDynamic = 10;
  print("dynamic型の変更後: $valueDynamic");
  
  // dynamic型ではエラーは出ない
  print("dynamic型の数値が偶数か否か: ${valueDynamic.isEven}");
  valueDynamic = 'Hello, Dynamic!';
  print("dynamic型の変更後: ${valueDynamic.length}");
  

  // 動作確認用 Object 型
  Object valueObject = "Hello, Object!"; // Object 型に文字列を代入
  print("Object型の初期値: $valueObject");
  valueObject = 10;
  print("Object型の変更後: $valueObject");
  
  // Object型ではエラーが発生する
  print("Object型の数値が偶数か否か: ${valueObject.isEven}");
  valueObject = 'Hello, Object!';
  print("Object型の文字列長さ: ${valueObject.length}");

  // 型チェックすればOK
  if (valueObject is String) {
    print("Object型の文字列長さ: ${valueObject.length}");
  }
}

dynamic型の場合

初期値として代入された valueDynamic は数値 10 なので、この時点では isEven プロパティの呼び出しは有効です。

しかし、valueDynamic が別の型(例えば文字列)に変更された場合、isEven プロパティはサポートされていないため、実行時にエラーが発生する。

valueDynamic が文字列であれば length プロパティは使用可能。
しかし、もし valueDynamic が数値や他の型に変更された場合、length プロパティは存在しないため、やはり実行時エラーが発生する。

Object型の場合

dynamic型と違い、isEven プロパティやlength プロパティを使用するとエラーが発生する。
これは型チェックが必要な為。
型チェックを行うと上記プロパティが使用できる。

つまり、型チェックを行うことが前提なので、dynamic型と比較し、安全なコードを書くことができる。


【参考】Object型の使い道

Object型はDartのすべての型のスーパータイプであり、型安全性を維持しつつ、汎用的な操作を行いたい場合に使用されます。

Object型の具体的な用途について解説します。Object型はDartのすべての型のスーパータイプであり、型安全性を維持しつつ、汎用的な操作を行いたい場合に使用されます。その用途を以下に詳しく説明します。


型が特定できない汎用的なデータを扱う場合

プログラムを設計していると、特定の型に依存せず、汎用的にデータを扱いたい場面が出てきます。Object型を使用すれば、どの型の値でも扱うことができ、型安全性を維持しつつ柔軟な操作が可能です。

例: 汎用的な関数

引数や戻り値にObject型を使用することで、どのような型の値にも対応可能な関数を作成できます。

void printObject(Object obj) {
  print('値: $obj');
  print('型: ${obj.runtimeType}');
}

void main() {
  printObject(42);             // 出力: 値: 42, 型: int
  printObject("Hello, Dart!"); // 出力: 値: Hello, Dart!, 型: String
  printObject([1, 2, 3]);      // 出力: 値: [1, 2, 3], 型: List<int>
}
  • 用途:
    • デバッグやロギング用の汎用関数。
    • 入力データの型に依存しない処理。

Mapやリストなどのコレクションで多様な型を格納する場合

Dartのコレクション(List, Mapなど)を使用する場合、デフォルトではObject型を使用して、異なる型のデータを格納できます。

例: Map<String, Object> を使用する

異なる型のデータを格納する場合にObject型を使えば柔軟なデータ構造を作成できます。

void main() {
  Map<String, Object> data = {
    'name': 'Alice',       // String型
    'age': 30,             // int型
    'isStudent': false,    // bool型
    'grades': [90, 85, 88] // List<int>型
  };

  print(data); // 出力: {name: Alice, age: 30, isStudent: false, grades: [90, 85, 88]}

  // 値の型に応じた処理
  data.forEach((key, value) {
    print('$key: $value (型: ${value.runtimeType})');
  });
}
  • 用途:
    • JSONやフォームデータなど、異なる型を持つデータ構造を扱う場合。
    • キーバリュー形式で多様なデータを格納する際の柔軟性。

型を事前に特定せずに操作したい場合

Object型を使用すれば、型を事前に特定する必要がありません。ただし、型に応じた操作を行う場合は、**型チェック(is)や型キャスト(as)**を使用する必要があります。

例: 型に応じた操作

Object型の値に対して、型をチェックし、適切な処理を行います。

void handleObject(Object obj) {
  if (obj is int) {
    print('整数: $obj, 偶数かどうか: ${obj.isEven}');
  } else if (obj is String) {
    print('文字列: $obj, 長さ: ${obj.length}');
  } else if (obj is List) {
    print('リスト: $obj, 要素数: ${obj.length}');
  } else {
    print('その他の型: $obj');
  }
}

void main() {
  handleObject(42);              // 出力: 整数: 42, 偶数かどうか: true
  handleObject("Hello, Dart!");  // 出力: 文字列: Hello, Dart!, 長さ: 12
  handleObject([1, 2, 3]);       // 出力: リスト: [1, 2, 3], 要素数: 3
  handleObject(true);            // 出力: その他の型: true
}
  • 用途:
    • 型に応じた動的な振る舞いを実現する。
    • 型が多様なデータを柔軟に処理する。

フレームワークやライブラリでの汎用的な引数や戻り値

フレームワークやライブラリでは、汎用的なAPIを提供するためにObject型が使用されることが多いです。たとえば、DartのFutureStreamクラスでは、非同期処理の結果としてObject型の値を返すことができます。

例: 非同期処理でのObject

非同期処理で多様な型の値を扱う場合にObject型を使用します。

Future<Object> fetchData() async {
  // 任意の型のデータを返す
  return "サーバーからのデータ";
}

void main() async {
  Object result = await fetchData();
  print('取得したデータ: $result');
}
  • 用途:
    • 汎用的なライブラリやAPIの設計。
    • 非同期処理やイベント駆動型プログラムで多様な型を扱う。

Null安全の下での使用

DartではObject型はnullを許容しません(Object?型を使用する必要があります)。これは、dynamic型やObject?型と区別される特徴です。

例: Null安全

void main() {
  Object value = "Hello"; // OK
  // value = null; // エラー: The value 'null' can't be assigned to a variable of type 'Object'.

  Object? nullableValue = null; // OK
  print(nullableValue); // 出力: null
}
  • 用途:
    • Null安全なコードを記述する際に、Object型を使用して型安全性を高める。

まとめ

・dynamic型は、コンパイル時に型チェックが行われないため非推奨
・Object型は、特定の型に依存せず、汎用的にデータを扱いたい場面で使用する
・基本的には型を明示的に指定したい

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?