Records
Record는 익명이고 불변인 집합 타입이다. Records는 크기가 고정되어 있고 여러 타입의 개체를 담을 수 있으며
Map, List, Set과 같은 컬렉션에 저장할 수 있다.
syntax
Record는 소괄호로 감싸져있고, 안의 요소들은 쉼표로 구분된다. 또한 위에서 말한 것처럼 여러 타입을 담을 수 있다.
Record 값은 dollar sign을 통해서 접근할 수 있다.
var records = ("first", true, 1); // (String, bool, int) records = ("first", true, 1);
print(records.$1); // first
print(records.$2); // true
print(records.$3); // 1
named fields
named field를 이용하여 Record를 선언하고 초기화하면 field를 통해 값에 접근할 수 있다. 또한 named field를 일반 field와 함께 사용할 수 있다. named field를 사용하는 방법은 함수를 선언할 때 named parameter를 지정하는 것과 동일하게 중괄호를 사용하면 된다.
({int a, int b}) record = (a: 1, b: 2); // var record = (a: 1, b: 2);
print(record.a); // 1
print(record.b); // 2
(String name, int age, {bool handsome}) me = ("yong", 28, handsome: false);
// var me = ("yong", 28, handsome: false);
Record type
Record를 사용하면 순서와 타입이 보장된다.
Record equality
두 개의 Record가 같은 형태를 가지고, 상응하는 필드의 값이 동일한 경우 두 Record는 동일하다.
(int a, int b, int c) record1 = (1, 2, 3);
(int d, int e, int f) record2 = (1, 2, 3);
print(record1 == record2); //true
Multiple returns
Record를 사용하면 여러 개의 값을 묶어서 반환할 수 있다. 반환된 Record 값은 Pattern Matching을 통해서 로컬 변수에 destructuring(비구조화)하여 할당 할 수 있다.
void main() {
final (name, age) = personInfo(json);
print(name); // "yong"
print(age); // 28
}
Map<String, dynamic> json = {
"name" : "yong",
"age" : 28,
"handsome" : false,
};
(String, int) personInfo(Map<String, dynamic> json) {
return (json["name"] as String, json["age"] as int);
}
Patterns
Pattern은 맥락과 모양에 따라 값을 매칭하거나, 비구조화하거나 둘 다 수행할 수 있게 한다.
Pattern Matching을 통해 다양한 형태의 destructuring이 가능하다.
final (name, age) = ("yong", 28);
print(name); // "yong"
print(age); // 28
왼쪽 Record와 오른쪽 Record 형태로 매칭을 시키면 name과 age에 값이 할당된다.
rest 키워드
리스트를 매칭할 때 ...를 사용하면 특정 범위를 생략하고 매칭이 가능하다.
final nums = [1, 2, 3, 4, 5, 6];
final [x, y, ..., z] = nums;
print(x); // 1
print(y); // 2
print(z); // 6
...뒤에 변수를 붙이면 생략된 값에 접근하여 사용할 수 있다.
final nums = [1, 2, 3, 4, 5, 6];
final [x, y, ...rest, z] = nums;
print(x); // 1
print(y); // 2
print(z) // 6
print(rest) // [3, 4, 5]
_를 사용하면 해당 위치의 값을 무시할 수 있다. -> 이를 Wildcard라고 함
final nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
final [x, _, _, y, ...rest, z, _, _] = nums;
print(x);
print(y);
print(z);
print(rest);
Map destructuring
Map도 형태만 맞추면 destructuring이 가능하다.
final me = {"name": "yong", "age": 28};
final {"name": name, "age": age} = me;
print(name); // "yong"
print(age); // 28
Class destructuring
void main() {
final Person(name: name, age: age) = const Person(name: "yong", age: 28);
print(name); // "yong"
print(age); // 28
}
class Person {
final String name;
final int age;
const Person({required this.name, required this.age});
}
Pattern Matching
위에서 설명한 destructuring도 Pattern Matching을 사용해서 진행했다. 하지만 Pattern Matching을 Dart 3.0 부터 switch 문을 통해 더 적극적으로 사용할 수 있다.
void switcher(dynamic anything) {
switch (anything) {
case [int a, int b]:
print("int $a, int $b");
case [_, _, _]:
print("match [_, _, _]");
case {"name":_}:
print("match {'name':_}");
case Person(name: String name, age: int age):
print("match person");
case > 10 && < 14:
print("match > 10 & < 14");
default:
print("no match");
}
}
또한 Dart 3.0부터 switch문 자체를 반환하여 사용할 수 있다. 단, switch 문 내부에서 반환 값이 있어야한다.
String switcher2(dynamic val, bool condition) => switch (val) {
5 when condition => "match 5",
_ => "no match",
};
case 문을 통해 Pattern Matching을 조건문 내부에서 사용할 수 있다.
final me = {
"name": "yong",
"age": 28,
};
if (me case {"name" : String _, "age" : int _}) {
print("match");
}
Class Modifier
final class
final로 클래스를 선언하면 extends, implements 또는 mixin으로 사용이 불가능하다.(같은 파일 내에서는 가능)
final class Person {
final String name;
final int age;
Person(this.name, this.age);
}
base class
base로 클래스를 선언하면 extend는 가능하지만 implements는 불가능하다.(같은 파일 내부에서는 모두 가능) 또한 base, sealed, final로 선언한 클래스만 extends가 가능하다.
base class Person {
final String name;
final int age;
Person(this.name, this.age);
}
interface
interface로 선언하면 implements만 가능하다.
interface class Person {
final String name;
final int age;
Person(this.name, this.age);
}
sealed class
sealed class는 final이면서 abstract이다.
sealed class Person{}
class Engineer extends Person {}
class Singer extends Person {}
그리고 패턴 매칭을 활용할 수 있다.(exhaustive class)
String practice(Person person) => switch(person) { // 컴파일 에러
Engineer e => "engineer",
}
String practice(Person person) => switch(person) { // 컴파일 에러 해결
Engineer e => "engineer",
_ => "가수" // == Singer s => "가수"
}
mixin class
mixin class에는 extends나 with를 사용할 수 없다.(mixin과 동일) 또한 class는 on 키워드를 사용할 수 없기 때문에 mixin class도 on 키워드를 사용할 수 없다.
mixin class PersonMixin {
void think() {
...
}
}
'Dart' 카테고리의 다른 글
Dart의 동시성 정리 - Isolate (0) | 2023.11.17 |
---|---|
Dart Compiler (0) | 2023.02.20 |