メインコンテンツにスキップ

コレクション

Dartは、リスト、セット、マップのコレクションをネイティブでサポートしています。コレクションが保持する型の設定について詳しくは、ジェネリクスをご覧ください。

リスト

#

おそらく、ほとんどのプログラミング言語で最も一般的なコレクションは、オブジェクトの順序付けられたグループである配列です。Dartでは、配列はListオブジェクトなので、ほとんどの人は単にリストと呼びます。

Dartのリストリテラルは、角括弧([])で囲まれたコンマ区切りの要素リストで表されます。各要素は通常、式です。以下に簡単なDartリストを示します。

dart
var list = [1, 2, 3];

Dartコレクションリテラルの最後の項目の後にコンマを追加できます。この末尾のコンマはコレクションに影響しませんが、コピー&ペーストのエラーを防ぐのに役立ちます。

dart
var list = ['Car', 'Boat', 'Plane'];

リストはゼロベースのインデックスを使用します。0は最初の要素のインデックスであり、list.length - 1は最後の要素のインデックスです。リストの長さは.lengthプロパティを使用して取得し、リストの要素にはサブスクリプト演算子([])を使用してアクセスできます。

dart
var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);

list[1] = 1;
assert(list[1] == 1);

コンパイル時定数であるリストを作成するには、リストリテラルの前にconstを追加します。

dart
var constantList = const [1, 2, 3];
// constantList[1] = 1; // This line will cause an error.

リストの詳細については、dart:coreドキュメントのリストセクションを参照してください。

セット

#

Dartのセットは、一意の要素の順序付けられていないコレクションです。Dartのセットのサポートは、セットリテラルとSet型によって提供されます。

以下に、セットリテラルを使用して作成された簡単なDartセットを示します。

dart
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};

空のセットを作成するには、型引数を前に付けた{}を使用するか、{}Set型の変数に代入します。

dart
var names = <String>{};
// Set<String> names = {}; // This works, too.
// var names = {}; // Creates a map, not a set.

既存のセットにアイテムを追加するには、add()またはaddAll()メソッドを使用します。

dart
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);

セット内のアイテム数を得るには.lengthを使用します。

dart
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
assert(elements.length == 5);

コンパイル時定数であるセットを作成するには、セットリテラルの前にconstを追加します。

dart
final constantSet = const {
  'fluorine',
  'chlorine',
  'bromine',
  'iodine',
  'astatine',
};
// constantSet.add('helium'); // This line will cause an error.

セットの詳細については、dart:coreドキュメントのセットセクションを参照してください。

マップ

#

マップでは、各要素はキーと値のペアです。各ペア内の各キーは値に関連付けられており、キーと値はどちらもあらゆる型のオブジェクトにすることができます。各キーは一度しか出現できませんが、同じ値が複数の異なるキーに関連付けられる可能性があります。Dartのマップのサポートは、マップリテラルとMap型によって提供されます。

以下に、マップリテラルを使用して作成された2つの簡単なDartマップを示します。

dart
var gifts = {
  // Key:    Value
  'first': 'partridge',
  'second': 'turtledoves',
  'fifth': 'golden rings',
};

var nobleGases = {2: 'helium', 10: 'neon', 18: 'argon'};

マップコンストラクタを使用して、同じオブジェクトを作成できます。

dart
var gifts = Map<String, String>();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';

var nobleGases = Map<int, String>();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';

サブスクリプト代入演算子([]=)を使用して、既存のマップに新しいキーと値のペアを追加します。

dart
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // Add a key-value pair

サブスクリプト演算子([])を使用して、マップから値を取得します。

dart
var gifts = {'first': 'partridge'};
assert(gifts['first'] == 'partridge');

マップに存在しないキーを検索すると、nullが返されます。

dart
var gifts = {'first': 'partridge'};
assert(gifts['fifth'] == null);

マップ内のキーと値のペアの数を得るには.lengthを使用します。

dart
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);

コンパイル時定数であるマップを作成するには、マップリテラルの前にconstを追加します。

dart
final constantMap = const {2: 'helium', 10: 'neon', 18: 'argon'};

// constantMap[2] = 'Helium'; // This line will cause an error.

マップの詳細については、dart:coreドキュメントのマップセクションを参照してください。

コレクション要素

#

コレクションリテラルには、一連の要素が含まれています。実行時に、各要素が評価され、ゼロ個以上の値が生成され、それらが結果のコレクションに挿入されます。これらの要素は、リーフ要素と制御フロー要素の2つの主なカテゴリに分類されます。

  • リーフ要素:個々のアイテムをコレクションリテラルに挿入します。

    • 式要素:単一の式を評価し、結果の値をコレクションに挿入します。

    • マップエントリ要素:キーと値の式のペアを評価し、結果のエントリをコレクションに挿入します。

  • 制御フロー要素:条件付きで、または繰り返し、ゼロ個以上の値を周囲のコレクションに追加します。

    • Null許容要素:式を評価し、結果がnullでない場合は、値を周囲のコレクションに挿入します。

    • スプレッド要素:指定されたシーケンス(コレクション式)を反復処理し、結果のすべての値を周囲のコレクションに挿入します。

    • Null許容スプレッド要素:スプレッド要素に似ていますが、コレクションをnullにすることができ、nullの場合は何も挿入しません。

    • If要素:条件式に基づいて内部要素を条件付きで評価し、条件が偽の場合はオプションで別のelse要素を評価します。

    • For要素:指定された内部要素を繰り返し評価し、ゼロ個以上の結果の値を挿入します。

コレクション要素について詳しくは、以下のセクションをご覧ください。

式要素

#

式要素は、単一の式を評価し、結果の値をコレクションに挿入します。この式には、リテラル、変数、演算子、関数呼び出し、コンストラクタ呼び出しなどのさまざまな構造を含めることができます。

式要素は、コレクション内でこの構文を持ちます。

dart
<expression>

マップエントリ要素

#

マップエントリ要素は、キーと値の式のペアを評価し、結果のエントリをコレクションに挿入します。このペア内のキーと値の両方が式になります。

マップエントリ要素は、コレクション内でこの構文を持ちます。

dart
<key_expression>: <value_expression>

Null許容要素

#

Null許容要素は、式を評価し、結果がnullでない場合は、周囲のコレクションに値を挿入します。

Null許容要素は、式要素内で次の構文を持ちます。

dart
?<expression>

Null許容要素は、マップエントリ要素内で次の構文を持ちます。

dart
// key is a null-aware element
?<key_expression>: <value_expression>
dart
// value is a null-aware element
<key_expression>: ?<value_expression>
dart
// key and value are null-aware elements
?<key_expression>: ?<value_expression>

次の例では、anullであるため、Null許容要素?aの結果はitemsという名前のリストに追加されません。

dart
int? absentValue = null;
int? presentValue = 3;
var items = [
  1,
  ?absentValue,
  ?presentValue,
  absentValue,
  5,
]; // [1, 3, null, 5]

次の例は、マップエントリ要素の内部でNull許容要素をさまざまな方法で使用する方法を示しています。

dart
String? presentKey = 'Apple';
String? absentKey = null;

int? presentValue = 3;
int? absentValue = null;

var itemsA = {presentKey: absentValue}; // {Apple: null}
var itemsB = {presentKey: ?absentValue}; // {}

var itemsC = {absentKey: presentValue}; // {null: 3}
var itemsD = {?absentKey: presentValue}; // {}

var itemsE = {absentKey: absentValue}; // {null: null}
var itemsF = {?absentKey: ?absentValue}; // {}

スプレッド要素

#

スプレッド要素は、指定されたシーケンスを反復処理し、結果のすべての値を周囲のコレクションに挿入します。

スプレッド要素は、コレクション内でこの構文を持ちます。シーケンス式は、Iterableを実装するオブジェクトに評価される任意の式を表すことができます。

dart
...<sequence_expression>

次の例では、aという名前のリストの要素がitemsという名前のリストに追加されます。

dart
var a = [1, 2, null, 4];
var items = [0, ...a, 5]; // [0, 1, 2, null, 4, 5]

nullになる可能性のある式をスプレッドしており、そのnullを無視したい(要素を挿入しない)場合は、Null許容スプレッド要素を使用してください。

スプレッド演算子について詳しくは、スプレッド演算子を参照してください。

Null許容スプレッド要素

#

Null許容スプレッド要素は、スプレッド要素に似ていますが、コレクションをnullにすることができ、nullの場合は何も挿入しません。

Null許容スプレッド要素は、コレクション内でこの構文を持ちます。

dart
...?<sequence_expression>

次の例では、aという名前のリストはnullであるため無視されますが、bという名前のリストの要素はitemsという名前のリストに追加されます。コレクション自体がnullではないが、nullの要素が含まれている場合、それらのnull要素は結果に追加されることに注意してください。

dart
List<int>? a = null;
var b = [1, null, 3];
var items = [0, ...?a, ...?b, 4]; // [0, 1, null, 3, 4]

Null安全のため、nullになる可能性のある値に対してスプレッド操作(...)を実行することはできません。次の例では、extraOptionsパラメータがnullableであり、extraOptionsに使用されているスプレッド演算子がNull許容でないため、コンパイル時エラーが発生します。

✗ 静的解析: 失敗dart
List<String> buildCommandLine(
  String executable,
  List<String> options, [
  List<String>? extraOptions,
]) {
  return [
    executable,
    ...options,
    ...extraOptions, // <-- Error
  ];
}

// Usage:
//   buildCommandLine('dart', ['run', 'my_script.dart'], null);
// Result:
//   Compile-time error

nullableなコレクションをスプレッドしたい場合は、Null許容スプレッド要素を使用してください。次の例は、extraOptionsでNull許容スプレッド演算子が使用されているため有効です。

dart
List<String> buildCommandLine(
  String executable,
  List<String> options, [
  List<String>? extraOptions,
]) {
  return [
    executable,
    ...options,
    ...?extraOptions, // <-- OK now.
  ];
}

// Usage:
//   buildCommandLine('dart', ['run', 'my_script.dart'], null);
// Result:
//   [dart, run, my_script.dart]

Null許容スプレッド演算子について詳しくは、スプレッド演算子を参照してください。

If要素

#

if要素は、条件式に基づいて内部要素を条件付きで評価し、条件が偽の場合はオプションで別のelse要素を評価します。

if要素にはいくつかの構文バリエーションがあります。

dart
// If the bool expression is true, include the result.
if (<bool_expression>) <result>
dart
// If the expression matches the pattern, include the result.
if (<expression> case <pattern>) <result>
dart
// If the operation resolves as true, include the first
// result, otherwise, include the second result.
if (<bool_expression>) <result> else <result>
dart
// If the operation resolves as true, include the first
// result, otherwise, include the second result.
if (<expression> case <pattern>) <result> else <result>

次の例は、ブール式を含むコレクション内でif要素をさまざまな方法で使用する方法を示しています。

dart
var includeItem = true;
var items = [0, if (includeItem) 1, 2, 3]; // [0, 1, 2, 3]
dart
var includeItem = true;
var items = [0, if (!includeItem) 1, 2, 3]; // [0, 2, 3]
dart
var name = 'apple';
var items = [0, if (name == 'orange') 1 else 10, 2, 3]; // [0, 10, 2, 3]
dart
var name = 'apple';
var items = [
  0,
  if (name == 'kiwi') 1 else if (name == 'pear') 10,
  2,
  3,
]; // [0, 2, 3]

次の例は、case部分を持つif要素をコレクション内でさまざまな方法で使用する方法を示しています。

dart
Object data = 123;
var typeInfo = [
  if (data case int i) 'Data is an integer: $i',
  if (data case String s) 'Data is a string: $s',
  if (data case bool b) 'Data is a boolean: $b',
  if (data case double d) 'Data is a double: $d',
]; // [Data is an integer: 123, Data is a double: 123]
dart
var word = 'hello';
var items = [
  1,
  if (word case String(length: var wordLength)) wordLength,
  3,
]; // [1, 5, 3]
dart
var orderDetails = ['Apples', 12, ''];
var summary = [
  'Product: ${orderDetails[0]}',
  if (orderDetails case [_, int qty, _]) 'Quantity: $qty',
  if (orderDetails case [_, _, ''])
    'Delivery: Not Started'
  else
    'Delivery: In Progress',
]; // [Product: Apples, Quantity: 12, Delivery: Not Started]

if操作とelse if部分を混在させることができます。たとえば、次のようになります。

dart
var a = 'apple';
var b = 'orange';
var c = 'mango';
var items = [
  0,
  if (a == 'apple') 1 else if (a case 'mango') 10,
  if (b case 'pear') 2 else if (b == 'mango') 20,
  if (c case 'apple') 3 else if (c case 'mango') 30,
  4,
]; // [0, 1, 30, 4]

if条件について詳しくは、ifステートメントを参照してください。if-case条件について詳しくは、if-caseステートメントを参照してください。

For要素

#

for要素は、指定された内部要素を繰り返し評価し、ゼロ個以上の結果の値を挿入します。

for要素は、コレクション内でこの構文を持ちます。

dart
for (<expression> in <collection>) <result>
dart
for (<initialization_clause>; <condition_clause>; <increment_clause>) <result>

次の例は、コレクション内でfor要素をさまざまな方法で使用する方法を示しています。

dart
var numbers = [2, 3, 4];
var items = [1, for (var n in numbers) n * n, 7]; // [1, 4, 9, 16, 7]
dart
var items = [1, for (var x = 5; x > 2; x--) x, 7]; // [1, 5, 4, 3, 7]
dart
var items = [1, for (var x = 2; x < 4; x++) x, 7]; // [1, 2, 3, 7]

forループについて詳しくは、forループを参照してください。

ネストされた制御フロー要素

#

制御フロー要素を互いにネストできます。これは、他の言語のリスト内包表記の強力な代替手段です。

次の例では、numbersの偶数のみがitemsに含まれます。

dart
var numbers = [1, 2, 3, 4, 5, 6, 7];
var items = [
  0,
  for (var n in numbers)
    if (n.isEven) n,
  8,
]; // [0, 2, 4, 6, 8]

ifまたはfor要素の直下にコレクションリテラルのスプレッドを使用することは一般的で慣用的です。たとえば、次のようになります。

dart
var items = [
  if (condition) oneThing(),
  if (condition) ...[multiple(), things()],
]; // [oneThing, [multiple_a, multiple_b], things]

あらゆる種類の要素を任意の深さまでネストできます。次の例では、iffor、およびスプレッド要素がコレクション内で互いにネストされています。

dart
var nestItems = true;
var ys = [1, 2, 3, 4];
var items = [
  if (nestItems) ...[
    for (var x = 0; x < 3; x++)
      for (var y in ys)
        if (x < y) x + y * 10,
  ],
]; // [10, 20, 30, 40, 21, 31, 41, 32, 42]