티스토리 뷰

반응형

레코드

레코드는 여러 객체를 묶어서 단일 객체로 만들어 준다. 레코드는 크기가 고정되고, 서로 다른 타입을 가질 수 있고, 타입이 된다. 따라서 레코드는 익명, 불변, 집합 타입이라는 특성을 가지게 된다.

 

레코드는 값이 된다. 레코드를 변수에 저장할 수 있고, 중첩할 수 있다. 그리고 매개변수 타입과 리턴 타입이 될 수 있다. 또한 리스트, 맵, 집하보가 같은 데이터 구조에 저장할 수도 있다.

 

 

 

레코드 구문

레코드 구문은 괄호 안에 쉼표로 구분된 이름 필드 또는 위치 필드로 이루어진다. 이름 필드는 이름과 값으로 이루어지고 위치 필드는 값으로만 이루어진다.

var record = ('first', a: 2, b:true, 'last');

 

 

레코드 타입 주석

레코드 타입 주석은 괄호 안에 쉼표로 구분된 타입으로 이루어 진다. 레코드 타입 주석을 사용해서 타입을 정의할 수 있다.

(int, int) swap((int, int) record) {
  var (a, b) = record;
  return (b, a);
}
(String, int) record;
record = ('string', 123);

 

 

명명된 레코드 타입 주석

레코드 타입 주석은 중괄호 안에 명명된 필드를 만들 수도 있다.

({int a, bool b)) record;
record = (a: 123, b: true);

 

명명된 필드 이름은 레코드 타입에 영향을 준다. 그래서 이름이 다른 필드를 가진 두 레코드의 타입은 서로 다르게 된다.

({int a, int b}) recordAB = (a: 1, b: 2);
({int x, int y}) recordXY = (x: 1, y: 2);

recordAB = recordXY;  // 타입이 달라서 에러가 발생한다.

 

중괄호를 사용하지 않고 명명된 필드 이름을 사용하면 문서화를 위한 용도로만 사용되고, 레코드 타입에 영향을 주지 않는다.

(int a, int b) recordAB = (1, 2);
(int x, int y) recordXY = (1, 2);

recordAB = recordXY;  // OK

 

 

 

레코드 필드

내장된 게터를 통해 레코드 필드에 엑세스할 수 있다. 레코드는 변경할 수 없으므로 세터는 없다.

 

명명된 필드의 게터는 동일한 필드 이름이 된다. 위치 필드는 $<위치> 이름의 게터가 된다. <위치>는 1부터 순차적으로 증가한다. 위치 필드 사이에 명명된 필드는 건너뛰게 된다.

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`.

 

 

 

레코드 동등성

두 레코드의 모양(필드, 필드 타입 및 이름)이 같고, 필드의 값들이 같은 경우, 두 레코드는 동일하게 된다.

(int x, int y, int z) point = (1, 2, 3);
(int r, int g, int b) color = (1, 2, 3);

print(point == color); // 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.

 

명명된 필드 순서는 레코드 모양에 영향을 주지 않으므로 명명된 필드 순서는 동등성에 영향을 주지 않는다.

({int x, int y, int z}) point = (x: 1, y: 2, z: 3);
({int x, int z, int y}) color = (x: 1, y: 2, z: 3);

print(point == color);  // true

 

 

 

집합 반환

레코드를 사용하면 함수가 여러 값을 묶어서 반환할 수 있게 된다. 반환된 레코드 값은 패턴 매치를 사용하여 값을 해체할 수 있다.

// 여러 값을 리코더로 반환한다.
(String, int) userInfo(Map<String, dynamic> json) {
  return (json['name'] as String, json['age'] as int);
}

final json = <String, dynamic>{
  'name': 'Dash',
  'age': 10,
  'color': 'blue',
};

// 레코드 패턴을 사용해서 해체하기
var (name, age) = userInfo(json);

 

레코드 패턴을 사용하지 않고, 다음과 같이 필드의 게터를 사용할 수도 있다.

var info = userInfo(json);
var name = info.$1;
var age  = info.$2;

 

 

클래스와 컬렉션 타입으로도 여러 값을 반환할 수도 있다. 하지만 클래스를 만드는 것은 시간이 오래 걸리고, 컬렉션 타입을 사용하면 타입 안전성이 손실된다.

 

반응형
댓글
공지사항