レコード
レコードは、匿名の、不変な、集約型です。他のコレクション型と同様に、複数のオブジェクトを1つのオブジェクトにまとめることができます。他のコレクション型とは異なり、レコードは固定サイズで、異種であり、型付けされています。
レコードは実際の値です。変数に格納したり、ネストしたり、関数に渡したり、関数から受け取ったり、リスト、マップ、セットなどのデータ構造に格納したりできます。
レコード構文
#レコード式は、名前付きまたは位置指定フィールドのカンマ区切りリストで、括弧で囲みます。
var record = ('first', a: 2, b: true, 'last');
レコード型注釈は、括弧で囲まれた型のカンマ区切りリストです。レコード型注釈を使用して、戻り値の型とパラメータの型を定義できます。たとえば、次の(int, int)
ステートメントはレコード型注釈です。
(int, int) swap((int, int) record) {
var (a, b) = record;
return (b, a);
}
レコード式と型注釈のフィールドは、関数におけるパラメータと引数の動作を反映しています。位置指定フィールドは括弧内に直接記述します。
// Record type annotation in a variable declaration:
(String, int) record;
// Initialize it with a record expression:
record = ('A string', 123);
レコード型注釈では、名前付きフィールドは、すべての位置指定フィールドの後に、型と名前のペアの中波括弧で囲まれたセクション内に記述します。レコード式では、名前は各フィールド値の前にコロンを付けて記述します。
// Record type annotation in a variable declaration:
({int a, bool b}) record;
// Initialize it with a record expression:
record = (a: 123, b: true);
レコード型の名前付きフィールドの名前は、レコードの型定義、つまりその*形状*の一部です。異なる名前の名前付きフィールドを持つ2つのレコードは、異なる型になります。
({int a, int b}) recordAB = (a: 1, b: 2);
({int x, int y}) recordXY = (x: 3, y: 4);
// Compile error! These records don't have the same type.
// recordAB = recordXY;
レコード型注釈では、*位置指定*フィールドにも名前を付けることができますが、これらの名前は純粋にドキュメント用であり、レコードの型には影響しません。
(int a, int b) recordAB = (1, 2);
(int x, int y) recordXY = (3, 4);
recordAB = recordXY; // OK.
これは、関数宣言または関数typedefの位置指定パラメータに名前を付けることができますが、それらの名前は関数のシグネチャに影響しないのと似ています。
詳細と例については、レコード型とレコードの等価性を参照してください。
レコードフィールド
#レコードフィールドには、組み込みゲッターを介してアクセスできます。レコードは不変であるため、フィールドにセッターはありません。
名前付きフィールドは、同じ名前のゲッターを公開します。位置指定フィールドは、名前付きフィールドをスキップして、$<position>
という名前のゲッターを公開します。
var record = ('first', a: 2, b: true, 'last');
print(record.$1); // Prints 'first'
print(record.a); // Prints 2
print(record.b); // Prints true
print(record.$2); // Prints 'last'
レコードフィールドアクセスをさらに合理化するには、パターンのページを参照してください。
レコード型
#個々のレコード型の型宣言はありません。レコードは、フィールドの型に基づいて構造的に型付けされます。レコードの*形状*(フィールドのセット、フィールドの型、および名前(存在する場合)) によって、レコードの型が一意に決まります。
レコードの各フィールドには、独自の型があります。フィールドの型は、同じレコード内で異なる場合があります。型システムは、レコードからアクセスされる場所であればどこでも、各フィールドの型を認識しています。
(num, Object) pair = (42, 'a');
var first = pair.$1; // Static type `num`, runtime type `int`.
var second = pair.$2; // Static type `Object`, runtime type `String`.
同じフィールドセットを持つレコードを作成する、関連のない2つのライブラリを考えてみます。型システムは、ライブラリが相互に結合されていなくても、それらのレコードが同じ型であることを理解します。
レコードの等価性
#2つのレコードは、同じ*形状*(フィールドのセット) を持ち、対応するフィールドが同じ値を持つ場合、等しいとみなされます。名前付きフィールドの*順序*はレコードの形状の一部ではないため、名前付きフィールドの順序は等価性に影響しません。
例えば
(int x, int y, int z) point = (1, 2, 3);
(int r, int g, int b) color = (1, 2, 3);
print(point == color); // Prints 'true'.
({int x, int y, int z}) point = (x: 1, y: 2, z: 3);
({int r, int g, int b}) color = (r: 1, g: 2, b: 3);
print(point == color); // Prints 'false'. Lint: Equals on unrelated types.
レコードは、フィールドの構造に基づいて、自動的に`hashCode`と`==`メソッドを定義します。
複数戻り値
#レコードを使用すると、関数は複数の値をまとめて返すことができます。戻り値からレコード値を取得するには、分割代入を使用して、パターンマッチングを使用してローカル変数に値を分割代入します。
// Returns multiple values in a record:
(String name, int age) userInfo(Map<String, dynamic> json) {
return (json['name'] as String, json['age'] as int);
}
final json = <String, dynamic>{
'name': 'Dash',
'age': 10,
'color': 'blue',
};
// Destructures using a record pattern with positional fields:
var (name, age) = userInfo(json);
/* Equivalent to:
var info = userInfo(json);
var name = info.$1;
var age = info.$2;
*/
パターンの型ページで詳しく説明されているコロン`:`構文を使用して、名前付きフィールドを使用してレコードを分割代入することもできます。
({String name, int age}) userInfo(Map<String, dynamic> json)
// ···
// Destructures using a record pattern with named fields:
final (:name, :age) = userInfo(json);
レコードを使用せずに、関数から複数の値を返すことはできますが、他の方法には欠点があります。たとえば、クラスの作成ははるかに冗長になり、`List`や`Map`などの他のコレクション型を使用すると、型の安全性が失われます。
特に明記されていない限り、このサイトのドキュメントはDart 3.5.3を反映しています。ページの最終更新日:2024-03-06。 ソースを表示 または 問題を報告する。