🤿

【Dart】Extension(拡張関数)の簡単な例

2020/12/16に公開

【Dart】Extension(拡張関数)

参考

簡単な利用例

  • 以下のクラスに、extensionを利用し、Stringクラスに外部から機能を追加したい
class Monster {
  String name;
  int hp;
  Monster(this.name, this.hp);
}

void main() {
  final monster = Monster('Slime', 5);
  print(monster);
  print(monster.name + ':' + monster.hp.toString());
}

実行結果

Instance of 'Monster'
Slime:5
  • 関数を追加
    • extension MonsterExt on String {}
      • 文字列からMonsterクラスへ変換可能かのboolを返却する関数(isMonsterText()
      • 文字列からMonsterクラスへ変換するMonsterを返却する関数(toMonster()
    • class Monster {}
      • 文字列からMonsterクラスのオブジェクトを作成するコンストラクタ(Monster.fromString(String s) {}
class Monster {
  String name;
  int hp;
  Monster(this.name, this.hp);

  Monster.fromString(String s) {
    name = s.split(':')[0];
    hp = int.parse(s.split(':')[1]);
  }
}

extension MonsterExt on String {
  bool isMonsterText() {
    if (this.split(':').length == 2) {
      if (int.tryParse(this.split(':')[1]) != null) {
        return true;
      }
    }
    print('正しく文字列にしてください。例 Slime:5');
    return false;
  }

  Monster toMonster() {
    return Monster.fromString(this);
  }
}

void main() {
  String monsterText = 'Slime:5';
  if (monsterText.isMonsterText()) {
    final monster = monsterText.toMonster();
    print(monster);
    print(monster.name + ':' + monster.hp.toString());
  }
}

実行結果

Instance of 'Monster'
Slime:5
  • 実際の利用は、ファイルを適宜分けて利用し、必要な際にimport
    • 上記コードをファイル分けした例

monster.dart

class Monster {
  String name;
  int hp;
  Monster(this.name, this.hp);

  Monster.fromString(String s) {
    name = s.split(':')[0];
    hp = int.parse(s.split(':')[1]);
  }
}

monster_ext.dart

import 'monster.dart';

extension MonsterExt on String {
  bool isMonsterText() {
    if (this.split(':').length == 2) {
      if (int.tryParse(this.split(':')[1]) != null) {
        return true;
      }
    }
    print('正しく文字列にしてください。例 Slime:5');
    return false;
  }

  Monster toMonster() {
    return Monster.fromString(this);
  }
}

main.dart

import 'monster_ext.dart';

void main() {
  String monsterText = 'Slime:5';
  if (monsterText.isMonsterText()) {
    final monster = monsterText.toMonster();
    print(monster);
    print(monster.name + ':' + monster.hp.toString());
  }
}

実行結果

Instance of 'Monster'
Slime:5
  • 【備考】extensionを利用する際
    • extends等では無く外部から変更を足したい状況や、コードの可読性等を考え利用
      • 例としたコードでは、実現にわざわざextenstionを利用せず、以下で可能
class Monster {
  String name;
  int hp;
  Monster(this.name, this.hp);

  static bool isMonsterText(String s) {
    if (s.split(':').length == 2) {
      if (int.tryParse(s.split(':')[1]) != null) {
        return true;
      }
    }
    print('正しく文字列にしてください。例 Slime:5');
    return false;
  }

  Monster.fromString(String s) {
    name = s.split(':')[0];
    hp = int.parse(s.split(':')[1]);
  }
}

void main() {
  String monsterText = 'Slime:5';
  if (Monster.isMonsterText(monsterText)) {
    final monster = Monster.fromString(monsterText);
    print(monster);
    print(monster.name + ':' + monster.hp.toString());
  }
}

実行結果

Instance of 'Monster'
Slime:5
  • 【備考】文字列からMonsterクラスへ変換可能かのboolを返却する関数をmain内で利用しないパターン
    • static bool isMonsterText(String s)で判断する関数を分けてはいるが、Monster.fromString(String s){}を不正な値で呼び出されてしまう可能性あり
      • 実際は、エラーハンドリング等必要
    • 間違っている場合も、何かしらのオブジェクトを作成する場合は以下としてもよい
      • Monster.fromString(String s){}の中で、bool isMonsterText(String s)を利用
class Monster {
  String name;
  int hp;
  Monster(this.name, this.hp);

  bool isMonsterText(String s) {
    if (s.split(':').length == 2) {
      if (int.tryParse(s.split(':')[1]) != null) {
        return true;
      }
    }
    print('正しく文字列にしてください。例 Slime:5');
    return false;
  }

  Monster.fromString(String s) {
    if (isMonsterText(s)) {
      name = s.split(':')[0];
      hp = int.parse(s.split(':')[1]);
    } else {
      print('xxx:0を仮作成');
      name = 'xxx';
      hp = 0;
    }
  }
}

void main() {
  final monster = Monster.fromString('Slime5');
  print(monster);
  print(monster.name + ':' + monster.hp.toString());
}

実行結果

正しく文字列にしてください。例 Slime:5
xxx:0を仮作成
Instance of 'Monster'
xxx:0

Discussion