Dart 3のswitch文:新たな表現力と安全性を求めて

はじめに

Dart 3が登場し、その中で特に注目すべき改良が施された部分が、switch文の大幅な強化です。これにより、パターンマッチングのような強力な表現力を得ることができました。伝統的なswitch文とは違い、各ケースの末尾にbreakを追加する必要がなくなりました。さらに、複数のケースを組み合わせるための論理演算子もサポートされるようになりました。

新たに搭載されたswitch文は、より洗練されたパターンマッチングにより、コードの表現力を一段と引き上げます。また、この新しいswitch文は全てのケースを網羅しているかをコンパイラが自動的にチェックし、これにより未想定のエラーを避けることが可能になりました。

この記事では、その新機能に焦点を当て、具体的な例を通じてその利用法と可能性をご紹介します。それでは、新たに進化したDart 3のswitch文の探索を始めましょう!

Dart 3 からswitch文新機能

パターン・マッチとbreakが不要

以下のように、一つのcaseの中に複数の項目を設定することができるようになりました。またbreakがなくて、次のcase を実行するようなことがなくなりました。

String switchCase(String value) {
    String result;
    switch (value) {
      case 'a':
            result = 'aa';
      case 'b' || 'c':
            result = 'bb';
      default:
            result = 'zz';
    }
    return result;
}

簡単な計算用のswitch

SQLのswitchのような書き方ができるようになりました。個人的には凄く嬉しい!

String switchReturn(String value) {
  return switch (value) { 'a' => 'aa', 'b' || 'c' => 'bb', _ => 'zz' };
}

網羅性のチェック

switch文が全てのcaseに対応しているかも確認してくれるようになりました。それはdefaultがなかったら、教えてくれる、というだけではありません。以下のようなenumのコードで、ABC.Xが一つでも欠ければコンパイルエラーになります。

enum ABC { a, b, c }

final result = switch (abc) { ABC.a => 'a', ABC.b => 'b', ABC.c => 'c' };

まとめ

Dart 3におけるswitch文の進化は、コードの表現力と安全性の両方を向上させ、より効率的な開発体験を提供します。強化されたパターンマッチング機能により、より明瞭かつ強力な制御フローの表現が可能となりました。また、breakが不要となったことで、コードの可読性が向上し、誤ったフロー制御によるバグを減らすことができます。

加えて、複数のケースを組み合わせるための論理演算子の導入により、switch文の柔軟性が増しました。これにより、より複雑な状況を効果的にハンドリングすることが可能となります。

さらに注目すべき改良として、全てのケースを網羅しているかのチェック機能があります。これは、コンパイラが自動的に実行し、全ての可能なケースが考慮されていない場合に警告またはエラーを発行します。これにより、思わぬバグを防ぎ、安全なコードを書くのを支援します。

これらの改良により、Dart 3のswitch文は、表現力、可読性、安全性の全てを強化しました。その結果、開発者はより高品質で効率的なコードを書くことができるようになりました。

参考

Dart 3を発表@Google I/O 2023

全ソース

import 'package:flutter_test/flutter_test.dart';

enum ABC { a, b, c }

void main() {
  String switchCase(String value) {
    String result;
    switch (value) {
      case 'a':
        result = 'aa';
      case 'b' || 'c':
        result = 'bb';
      default:
        result = 'zz';
    }
    return result;
  }

  String switchReturn(String value) {
    return switch (value) { 'a' => 'aa', 'b' || 'c' => 'bb', _ => 'zz' };
  }

  test('switch case', () {
    expect(switchCase('a'), 'aa');
    expect(switchCase('b'), 'bb');
    expect(switchCase('c'), 'bb');
    expect(switchCase('d'), 'zz');
  });

  test('switch return', () {
    expect(switchReturn('a'), 'aa');
    expect(switchReturn('b'), 'bb');
    expect(switchReturn('c'), 'bb');
    expect(switchReturn('d'), 'zz');
  });

  test('switch checkAll', () {
    final abc = ABC.a;
    final result = switch (abc) { ABC.a => 'a', ABC.b => 'b', ABC.c => 'c' };
    expect(result, 'a');
  });
}