dart-idiomatic-usage について
Dart で慣用的な文字列やコレクションを書くためのスキルです。簡潔な構築、反復処理、型の扱いと、既存コードのリファクタリング手順を扱います。
主な機能
- 01文字列補間とリテラルの連結
- 02スプレッドと制御構文によるコレクション構築
- 03空判定と反復処理の効率化
- 04コレクションの型変換指針
- 05既存コレクションのリファクタリング手順
活用シーン
- 01Dart コードの文字列連結のリファクタリング
- 02命令型のコレクション構築の置き換え
- 03既存のコレクション操作やキャストの更新
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ dart-lang/ skills --skill dart-idiomatic-usageインストール後、Claude Code で/dart-idiomatic-usageを入力して読み込まれたか確認します。
詳細
慣用的な Dart のコレクションと文字列の記述
目次
文字列の組み立て
文字列を効率的かつ読みやすく組み立てるには、次のプラクティスに従ってください。
- 隣接する文字列で連結する: 文字列リテラルの連結に
+演算子を使用しないでください。文字列を並べて、ひとつの文字列として記述します。 - 文字列補間を優先する: 文字列や値を組み立てるときは、連結(
+)ではなく$variableまたは${expression}を使用します。 - 不要な波括弧を省略する: 単純な識別子の直後に英数字が続かない場合は、
${identifier}ではなく$identifierを使用します。
例
推奨:
// Adjacent strings
raiseAlarm(
'ERROR: Parts of the spaceship are on fire. Other '
'parts are overrun by martians. Unclear which are which.',
);
// Interpolation without unnecessary braces
var greeting = 'Hi, $name! I love your ${decade}s costume.';
非推奨:
// Do not use + for literals or variables
raiseAlarm(
'ERROR: Parts of the spaceship are on fire. Other ' +
'parts are overrun by martians. Unclear which are which.',
);
var greeting = 'Hi, ' + name + '! I love your ' + decade.toString() + 's costume.';
var badBraces = 'Hi, ${name}!';
コレクションの初期化
Dart に組み込まれている構文を活用して、コレクションを作成し、構成します。
- コレクションリテラルを使用する: 名前なしコンストラクター(例:
Map()、Set())ではなく、[]、{}、<Type>{}を使ってリスト、マップ、セットをインスタンス化します。 - スプレッド演算子と制御フロー演算子を使用する:
add()やaddAll()のような命令型の呼び出しではなく、スプレッド演算子(...、...?)とコレクション内のif/forを使って動的なコレクションを構築します。
例
推奨:
var points = <Point>[];
var addresses = <String, Address>{};
var arguments = [
...options,
command,
...?modeFlags,
for (var path in filePaths)
if (path.endsWith('.dart')) path.replaceAll('.dart', '.js'),
];
非推奨:
var addresses = Map<String, Address>();
var arguments = <String>[];
arguments.addAll(options);
arguments.add(command);
if (modeFlags != null) arguments.addAll(modeFlags);
コレクションの操作
コレクションの検索と反復処理を最適化します。
.isEmptyと.isNotEmptyを使用する: コレクションの.lengthが0または> 0かどうかを決して確認しないでください。Iterableの契約では、長さの計算が定数時間であることは保証されません。- 関数リテラルを使った
Iterable.forEach()は避ける: シーケンスを反復処理する際は、標準的なfor-inループを使用します。forEach()は既存関数のティアオフを渡す場合(例:people.forEach(print))に使用します。 whereType<T>()を使用する:where((e) => e is T)ではなく、組み込みのwhereType<T>()メソッドを使って、型によってコレクションをフィルタリングします。
例
推奨:
if (lunchBox.isEmpty) return 'so hungry...';
for (final person in people) {
process(person);
}
var ints = objects.whereType<int>();
非推奨:
if (lunchBox.length == 0) return 'so hungry...';
people.forEach((person) {
process(person);
});
var ints = objects.where((e) => e is int).cast<int>();
コレクションの型キャスト
.cast<T>() は、操作のたびに要素の型を確認する遅延コレクションを作成し、パフォーマンスを低下させるため、使用を最小限に抑えてください。
- 正しい型で作成する: インスタンス化時に、コレクションを正しいジェネリック型で定義します。
List.from()を使って即時にキャストする: コレクションを変換する必要があり、その要素の大半にアクセスする場合は、List<T>.from(iterable)またはMap<K, V>.from(map)を使って、要素を一度に即時キャストします。.toList()で型を維持する: 元の型を維持したままイテラブルをコピーする場合は、.toList()を使用します。List.from()は、意図的に型を変更する場合にのみ使用します。
例
推奨:
// Eager cast
var stuff = <dynamic>[1, 2];
var ints = List<int>.from(stuff);
// Map with explicit type
var reciprocals = stuff.map<double>((n) => n * 2);
非推奨:
// Lazy cast (performance hit on every access)
var stuff = <dynamic>[1, 2];
var ints = stuff.toList().cast<int>();
var reciprocals = stuff.map((n) => n * 2).cast<double>();
ワークフロー:レガシーコレクションのリファクタリング
レガシーな Dart コードを最新の標準に更新する際は、次の順序付きチェックリストに従ってください。
タスクの進捗
- ステップ 1:コンストラクターを置き換える。
Map()、Set()、および(該当する場合)List()を検索します。<K, V>{}、<T>{}、<T>[]に置き換えます。 - ステップ 2:
.lengthのチェックをなくす。.length == 0、.length > 0、.length != 0を正規表現で検索します。.isEmptyまたは.isNotEmptyに置き換えます。 - ステップ 3:命令型の構築を簡潔にする。 新しくインスタンス化したコレクションに対する、連続した
.add()および.addAll()の呼び出しを特定します。コレクションリテラル内で...、if、forを使う形に書き換えます。 - ステップ 4:
.cast<T>()を削除する。.cast<を検索します。.toList()の後に適用されている場合は、List<T>.from()に置き換えます。.where()の後に適用されている場合は、.whereType<T>()に置き換えます。.map()の後に適用されている場合は、map の呼び出しにジェネリック型を追加します:.map<T>(...)。
- ステップ 5:バリデーターを実行し、エラーを確認して修正する。
dart analyzeを実行して、リファクタリング中に型の昇格や構文のエラーが発生していないことを確認します。
コメント
Markdown 対応