目次

健全ではない null セーフティ

Dart プログラムには、null セーフティ なライブラリとそうでないライブラリが混在している場合があります。これらの **複数バージョンのプログラム** は、**健全ではない null セーフティ** に依存しています。

言語バージョン を混在させる機能により、パッケージのメンテナーは、レガシーユーザーでも新しいバグ修正やその他の改善を得ることができるという認識のもと、コードを移行することができます。ただし、複数バージョンのプログラムでは、null セーフティによってもたらされるすべての利点を得られるわけではありません。

このページでは、健全な null セーフティと健全ではない null セーフティの違いについて説明し、null セーフティに移行する時期を決定するのに役立てます。概念的な説明の後、段階的な移行の手順、複数バージョンのプログラムのテストと実行に関する詳細が続きます。

健全な null セーフティと健全ではない null セーフティ

#

Dart は、静的チェックとランタイムチェックを組み合わせて、健全な null セーフティを提供します。null セーフティを選択した各 Dart ライブラリは、null セーフではないライブラリを含む複数バージョンのプログラムであっても、すべての *静的* チェックと、より厳密なコンパイル時エラーを受け取ります。コードの一部を null セーフティに移行し始めるとすぐに、これらの利点が得られます。

ただし、複数バージョンのプログラムは、完全に null セーフなアプリが持つ *ランタイム* の健全性保証を持つことはできません。null セーフではないライブラリから null セーフなコードに `null` がリークする可能性があります。これを防ぐと、移行されていないコードの既存の動作が壊れてしまうためです。

レガシーライブラリとのランタイム互換性を維持しながら、完全に null セーフなプログラムに健全性を提供するために、Dart ツールは 2 つのモードをサポートしています。

  • 複数バージョンのプログラムは、**健全ではない null セーフティ** で実行されます。ランタイムに `null` 参照エラーが発生する可能性がありますが、これは `null` または null 許容型が null セーフではないライブラリからエスケープして null セーフなコードに入ったためです。

  • プログラムが完全に移行され、*すべて* のライブラリが null セーフになると、**健全な null セーフティ** で実行され、健全性によってもたらされるすべての保証とコンパイラの最適化が有効になります。

可能な場合は、健全な null セーフティが望ましいです。プログラムのメインエントリポイントライブラリが null セーフティを選択している場合、Dart ツールはプログラムを自動的に健全モードで実行します。null セーフではないライブラリをインポートすると、ツールは健全ではない null セーフティでしか実行できないことを警告します。

段階的な移行

#

Dart は複数バージョンのプログラムをサポートしているため、プログラムとそのテストを実行できる状態で、一度に 1 つのライブラリ (通常は 1 つの Dart ファイル) を移行できます。

**最初にリーフライブラリ** (パッケージから他のファイルをインポートしないライブラリ) を移行することをお勧めします。次に、リーフライブラリに直接依存するライブラリを移行します。最後に、パッケージ内依存関係が最も多いライブラリを移行します。

たとえば、他の (null セーフな) パッケージとコアライブラリをインポートするが、`import '<local_path>'` ディレクティブがない `lib/src/util.dart` ファイルがあるとします。最初に `util.dart` を移行し、次に `util.dart` のみに依存するファイルを移行することを検討してください。ライブラリに循環インポートがある場合 (たとえば、A が B をインポートし、B が C をインポートし、C が A をインポートする場合)、これらのライブラリを一緒に移行することを検討してください。

移行ツールの使用

#

移行ツール を使用して段階的に移行できます。ファイルまたはディレクトリを除外するには、緑色のチェックボックスをクリックします。次のスクリーンショットでは、`bin` ディレクトリ内のすべてのファイルが除外されています。

Screenshot of file viewer in migration tool

除外された各ファイルは、2.9 言語バージョンコメント を除いて変更されません。後で `dart migrate` を再度実行して移行を続行できます。既に移行されたファイルには、無効になっているチェックボックスが表示されます。移行されたファイルは、移行を解除することはできません。

手動での移行

#

パッケージを手動で段階的に移行する場合は、次の手順に従います。

  1. パッケージの `pubspec.yaml` ファイルを編集し、最小 SDK 制約を少なくとも `2.12.0` に設定します。

    yaml
    environment:
      sdk: '>=2.12.0 <3.0.0'
  2. パッケージ構成ファイル を再生成します。

    $ dart pub get

    SDK 制約を `2.12.0` 以下に設定して `dart pub get` を実行すると、パッケージ内のすべてのライブラリのデフォルトの言語バージョンが 2.12 に設定され、null セーフティが有効になります。

  3. IDE でパッケージを開きます。
    多くの解析エラーが表示される可能性があります。これは問題ありません。

  4. 現在の移行中に考慮したくない Dart ファイルの先頭に 言語バージョンコメント を追加します。

    dart
    // @dart=2.9

    2.12 パッケージ内のライブラリに言語バージョン 2.9 を使用すると、移行されていないコードからの解析エラー (赤い波線) を減らすことができます。ただし、**健全ではない null セーフティは、アナライザーが使用できる情報を減らします。** たとえば、アナライザーは、2.9 ファイルが null 値を渡す可能性がある場合でも、パラメーター型が null 不可と見なす場合があります。

  5. アナライザーを使用して静的エラーを特定し、各 Dart ファイルのコードを移行します。
    必要に応じて、`?`、`!`、`required`、`late` を追加して静的エラーを解消します。

複数バージョンのプログラムのテストまたは実行

#

複数バージョンのコードをテストまたは実行するには、健全な null セーフティを無効にする必要があります。これは 2 つの方法で行うことができます。

  • `dart` または `flutter` コマンドに `--no-sound-null-safety` フラグを使用して健全な null セーフティを無効にします。

    $ dart --no-sound-null-safety run
    $ flutter run --no-sound-null-safety
  • または、エントリポイント (`main()` 関数が含まれているファイル) の言語バージョンを 2.9 に設定します。Flutter アプリでは、このファイルは多くの場合 `lib/main.dart` という名前です。コマンドラインアプリでは、このファイルは多くの場合 `bin/<packageName>.dart` という名前です。`test` 以下のファイルもエントリポイントであるため、除外することもできます。例:

    dart
    // @dart=2.9
    import 'src/my_app.dart';
    
    void main() {
      //...
    }

これらのいずれかのメカニズムを使用してテストを除外すると、段階的な移行プロセス *中* のテストに役立ちますが、そうすると、完全な null セーフティを有効にした状態でコードをテストできなくなります。ライブラリの段階的な移行が完了したら、テストを null セーフティに *戻す* ことが重要です。