マクロ (試験的機能)
Dartマクロシステム は、現在開発中の主要な新しい言語機能であり、Dart言語に静的メタプログラミングのサポートを追加します。
Dartマクロは、他のコードを引数として受け取り、リアルタイムで操作して宣言を作成、変更、または追加する、ユーザー定義のコードです。
マクロシステムは、マクロの使用とマクロの記述の2つの部分で考えることができます。このページでは、それぞれについて(この機能はまだプレビュー段階であるため、概要レベルで)以下のセクションで説明します。
`JsonCodable` マクロ: Dartでよくある面倒なJSONシリアライズとデシリアライズの問題に対するシームレスなソリューションを提供する、すぐに使えるマクロです(試験的フラグの背後で)。
マクロ機能全般: なぜDartにマクロを追加するのか、動機となるユースケース、既存のコード生成ソリューションに対する利点、そして機能が完成した後のマクロの記述方法の概要について説明します。
`JsonCodable` マクロ
#`JsonCodable` マクロは、ユーザー定義のDartクラスを `Map<String, Object?>` 型のJSONマップにエンコードおよびデコードします。2つのメンバー、`toJson` シリアライズメソッドと `fromJson` デシリアライズコンストラクタを生成します。
実験の設定
#Dart devチャンネルまたはFlutterマスターチャンネルに切り替えます。
`dart --version` を実行し、Dartバージョンが `3.5.0-152` 以降であることを確認します。
pubspecのSDK制約を編集して、Dartバージョン `sdk: ^3.5.0-152` を必須にします。
パッケージを追加する `json` を `dependencies` に追加します: `dart pub add json`.
プロジェクトのルートにあるパッケージの `analysis_options.yaml` ファイルで実験を有効にします。
yamlanalyzer: enable-experiment: - macros
使用するファイルにパッケージをインポートします
dartimport 'package:json/json.dart';
実験フラグを付けてプロジェクトを実行します
dart run --enable-experiment=macros bin/my_app.dart
マクロの使用
#`JsonCodable` マクロを使用するには、シリアライズするクラスにアノテーションを付けます
import 'package:json/json.dart';
@JsonCodable() // Macro annotation.
class User {
final int? age;
final String name;
final String username;
}
マクロは `User` クラスをイントロスペクトし、`User` クラスのフィールドを使用して `fromJson` と `toJson` の実装を導き出します。
そのため、自分で定義する必要なく、アノテーションが付けられたクラスのオブジェクトで `toJson` と `fromJson` を使用できるようになりました。
void main() {
// Given some arbitrary JSON:
var userJson = {
'age': 5,
'name': 'Roger',
'username': 'roger1337'
};
// Use the generated members:
var user = User.fromJson(userJson);
print(user);
print(user.toJson());
}
生成されたコードの表示
#マクロの仕組みをより深く理解したり、提供される内容の詳細を調べたりするために、生成されたコードを表示すると便利な場合があります。
IDE(VSCodeでサポート)のアノテーションの下に表示される「拡張機能に移動」リンクをクリックして、マクロが `toJson` と `fromJson` をどのように生成するかを確認します。
アノテーション付きクラスの内容を変更すると、生成された拡張機能がアプリケーションコードと並行してリアルタイムで調整されるのを確認できます。
カスタム診断のトリガー
#`JsonCodable` マクロには、言語自体からの診断と同様に発行される組み込み診断があります。たとえば、マクロが適用されている場所に手動で `toJson` メソッドを宣言しようとすると、アナライザーはエラーを発行します。
@JsonCodable()
class HasToJson {
void toJson() {}
// Error: Cannot generate a toJson method due to this existing one.
}
`JsonCodable` の定義で「`DiagnosticMessage`」を検索すると、マクロがスローする他のエラーを見つけることができます。たとえば、シリアライズ可能でないクラスを拡張する場合、またはフィールド名が指定されたJSONのキー名と正確に一致しない場合などです。
マクロ言語機能
#Dartマクロは、*静的*メタプログラミング、つまりコード生成ソリューションです。*ランタイム*コード生成ソリューション(build_runnerなど)とは異なり、マクロはDart言語に完全に統合されており、Dartツールによってバックグラウンドで自動的に実行されます。これにより、マクロはセカンダリツールに依存するよりもはるかに効率的になります。
- 実行するものは何もありません。マクロはコードを記述するときにリアルタイムでビルドされます。
- 重複作業やパフォーマンスを低下させるコンパイルの繰り返しはありません。すべてのビルドとコード生成はコンパイラ内で直接、自動的に行われます。
- ディスクに書き込まれません。したがって、生成された参照への部分ファイルやポインターはありません。マクロは*既存の*クラスを直接拡張します。
- 混乱したり難読化されたテストはありません。カスタム診断は、アナライザーからの他のメッセージと同様に、IDEに直接発行されます。
また、これらのタイプの問題に対するソリューションを自分で手動で記述するよりも、はるかに効率的でエラーが発生しにくいです。
ユースケース
#マクロは、面倒な定型コードと、多くの場合クラスのフィールドを反復処理する必要があるというパターンに対処するための再利用可能なメカニズムを提供します。今後マクロで解決したいと考えている一般的な例をいくつか挙げます。
JSONシリアライズ。 json_serializable パッケージのような、JSONをシリアライズするために必要な追加のツールは、本来あるべきほど効率的ではありません。`JsonCodable` マクロは、シリアライズコードを生成するためのよりクリーンな方法を提供します。今日試してみてください。
データクラス。 Dartの最も要望の多い機能は、コンストラクタと、各フィールドの `==`、`hashCode`、`copyWith()` メソッドの実装を自動的に提供するデータクラスです。マクロを使用してソリューションを実装することで、ユーザーはデータクラスを自由にカスタマイズできます。
冗長なFlutterパターン。 一例として、複雑な `build` メソッドを小さなウィジェットクラスの集合に分割することが挙げられます。これはパフォーマンスの向上とコードの保守性の向上につながります。残念ながら、これらの小さなクラスをすべて記述するには、大量の定型コードが必要になり、ユーザーの負担になります。マクロは、複雑な `build` メソッドを反復処理して小さなウィジェットクラスを生成するソリューションを提供できる可能性があり、Flutterコードの生産性と品質を大幅に向上させます。Flutterチームからのこの提案で、このトピックに関する調査を確認できます。
マクロの仕組み
#マクロを作成するには、`macro` キーワードを使用して、クラスと同様にマクロ宣言を記述します。マクロ宣言には、マクロを適用できるインターフェースを定義するための `implements` 句も含まれている必要があります。
たとえば、クラスに適用可能で、クラスに新しい宣言を追加するマクロは、`ClassDeclarationsMacro` インターフェースを実装します。
macro class MyMacro implements ClassDeclarationsMacro {
const MyMacro();
// ...
}
この機能はまだ開発中ですが、マクロインターフェースの完全なリストはソースコードにあります。
上記の例の `MyMacro` コンストラクタは、宣言にマクロを適用するために使用するアノテーションに対応しています。構文は、Dartの既存のメタデータアノテーション構文と同じです。
@MyMacro()
class A {}
マクロ宣言の本体内では、マクロに生成させたいコードと、マクロに発行させたい診断を定義します。
非常に高いレベルで言うと、マクロの記述は基本的に、ビルダーメソッドを使用して、宣言の*プロパティ*をそれらのプロパティの*識別子*と組み合わせることによって機能します。マクロは、プログラムの深いイントロスペクション(自己反映)を通じてこの情報を収集します。
マクロはまだ開発中のため、現時点ではこれ以上の詳細をお伝えすることはできません。ご興味がある場合、または実験的なフラグを使用してご自身で試してみたい場合は、既存のマクロの実装を確認することをお勧めします。
タイムライン
#マクロの安定版リリース日は現在不明です。これは、実装の複雑さによるものです。
マクロは、適用されるプログラムを深くイントロスペクション(自己反映)することによって機能します。マクロは、拡張している宣言のプロパティと型注釈に関する必要な情報を収集するために、プログラムの遠く離れた部分を巡回することになる場合があります。
大規模なコードベースでの適用を考えると、複数のマクロが異なる場所でベースを継続的にイントロスペクションおよび拡張できるため、実行順序と実行フェーズの設計は特に困難であり、慎重な検討が必要です。
JsonCodable
マクロの安定版リリースは今年(2024年)後半、そして言語機能全体(つまり、独自のマクロを記述する機能)の安定版リリースは来年初頭(2025年)に予定しています。
特に明記されていない限り、このサイトのドキュメントはDart 3.5.3を反映しています。ページの最終更新日:2024年10月22日。 ソースを表示 または 問題を報告する。