From 4ae8238067022d71cd09919d8f8266b1621dc200 Mon Sep 17 00:00:00 2001 From: Roo Ryu <34956359+deepbig@users.noreply.github.com> Date: Mon, 29 Jul 2024 00:35:17 +0900 Subject: [PATCH] Create ch04.md --- .../ch04.md" | 366 ++++++++++++++++++ 1 file changed, 366 insertions(+) create mode 100644 "hong/flutter/\354\275\224\353\223\234\355\214\251\353\217\204\353\246\254\354\235\230 \355\224\214\353\237\254\355\204\260 \355\224\204\353\241\234\352\267\270\353\236\230\353\260\215/ch04.md" diff --git "a/hong/flutter/\354\275\224\353\223\234\355\214\251\353\217\204\353\246\254\354\235\230 \355\224\214\353\237\254\355\204\260 \355\224\204\353\241\234\352\267\270\353\236\230\353\260\215/ch04.md" "b/hong/flutter/\354\275\224\353\223\234\355\214\251\353\217\204\353\246\254\354\235\230 \355\224\214\353\237\254\355\204\260 \355\224\204\353\241\234\352\267\270\353\236\230\353\260\215/ch04.md" new file mode 100644 index 0000000..ac22817 --- /dev/null +++ "b/hong/flutter/\354\275\224\353\223\234\355\214\251\353\217\204\353\246\254\354\235\230 \355\224\214\353\237\254\355\204\260 \355\224\204\353\241\234\352\267\270\353\236\230\353\260\215/ch04.md" @@ -0,0 +1,366 @@ +# 04. 다트 3.0 신규 문법 + +**학습 목표** + +- 플러터 3.0 버전 부터는 다트 3.0 버전 이상을 사용함. +- 그리고 다트 언어의 메이저 버전이 3으로 업데이트되면서 새로 추가된 문법들이 생김. + +### 4.1. 레코드 + +- Record: 다트 3.0 이상부터 사용할 수 있는 새로운 타입. +- 레코드는 positional parameter 또는 named parameter 중 한 가지 방식을 적용하여 사용할 수 있음. + +**4.1.1. 포지셔널 파라미터를 이용한 레코드** + +- 포지셔널 파라미터를 이용한 레코드는 포지셔널 파라미터로 표시한 타입 순서를 반드시 지켜야 함. +- 다음은 String, int 순서로 데이터를 입력해야 하는 레코드를 선언하는 예: + +```dart +void main() { + // 정확한 위치에 어떤 타입의 값이 입력될지 지정할 수 있음. + (String, int) roo = ('roo', 10); + + print(roo); // 결괏값: ('roo', 10) +} +``` + +- 레코드에 정의한 순서대로 타입을 입력하지 않으면 에러 발생함. +- 두 개 이상의 값을 조합해서 레코드를 만들 수도 있음. 레코드에 정의할 수 있는 값의 개수에는 제한이 없음. +- 레코드의 모든 값을 사용하지 않고 특정 순서의 레코드 값을 가져오고 싶다면 `$` 를 사용하면 됨. + +```dart +void main() { + (String, int, bool) roo = ('roo', 10, true); + + print(roo.$1); // roo + print(roo.$2); // 10 + print(roo.$3); // true +} +``` + +**4.1.2. 네임드 파라미터를 이용한 레코드** + +- 네임드 파라미터는 소괄호에 중괄호를 중첩하여 타입과 변수 이름을 쉼표로 구분하고 명시해줘야 함. + +```dart +void main() { + ({String name, int age}) roo = (name: 'roo', age: 10); + + print(roo); // (age: 10, name: roo) +} +``` + +## 4.2. 구조 분해 + +- 구조 분해(destructuring)는 값을 반환받을 때 단순히 하나의 변수로 받아오지 않음. +- 반환된 타입을 그대로 복제해서 타입 내부에 각각의 값을 직접 추출해오는 문법. + +4.2.1. 리스트에서의 구조 분해 사용 + +```dart +void main() { + final [roo, loo] = ['roo', 'loo']; + + print(roo); // roo + print(loo); // loo +} +``` + +4.2.2. 리스트에서의 스프레드 연산자를 이용한 구조 분해 사용 + +```dart +void main() { + final numbers = [1, 2, 3, 4, 5, 6, 7, 8]; + + // 스프레드 연산자를 사용해서 중간의 값들을 버리기 + final [x, y, ..., z] = numbers; + + print(x); // 1 + print(y); // 2 + print(z); // 8 +} +``` + +4.2.3. 맵에서의 구조 분해 사용 + +```dart +void main() { + final rooMap = {'name': 'roo', 'age': 10}; + // 위 구조와 같은 구조로 구조 분해하기 + final {'name': name, 'age': age} = rooMap; + + print('name: $name'); // name: roo + print('age: $age'); // age: 10 +} +``` + +4.2.4. 클래스에서의 구조 분해 사용 + +```dart +void main() { + final roo = Idol(name: 'roo', age: 10); + + // 클래스의 생성자 구조와 똑같이 구조 분해하기 + final Idol(name: name, age: age) = roo; + + print(name); + print(age); +} +``` + +## 4.3. switch 문 + +- switch 문은 다트 언어가 3.0. 버전으로 업데이트되면서 스위치 표현식(switch expression), 패턴 매칭(pattern matching), 완전 확인(exhaustiveness checking), 가드 절(guard clause) 네 가지가 추가 됨. + +**4.3.1. 표현식 기능** + +- 코드는 표현식(expression)과 문(statement)으로 나눌 수 있음. +- expression: + - 표현식은 어떠한 값을 만들어내는 코드. + - 예를 들어 1 + 1은 값 2를 만드는 표현식. + - 이처럼 표현식이 평가되면 새로운 값을 생성하거나 기존 값을 참조함. +- statement: + - 기본 단위이자 가장 작은 코드 실행 단위로 명령문(컴퓨터에 내리는 명령)을 뜻함. + - 표현식 여러 개가 모여 statement가 됨. + - statement의 종류: 선언문, 할당문, 반복문 +- 다트 3.0부터는 switch 문을 함수처럼 사용하여 직접 값을 반환받을 수 있는 절 기능이 추가됨. + +```dart +void main() { + String dayKor = '월요일'; + + // switch문이 함수처럼 값을 반환함. + String dayEnglish = switch (dayKor) { + // '=>'를 사용하면 switch 문 조건에 맞을 때 값을 반환할 수 있음. + '월요일' => 'Monday', + '화요일' => 'Tuesday', + // _ 는 default와 같은 의미로 사용됨. + _ => 'Not Found', + }; + + print(dayEnglish); // Monday +} +``` + +**4.3.2. 패턴 매칭** + +- 패턴 매칭(pattern matching) = 다트 3.0에 추가된 기능. 특히 switch 문을 사용할 때 패턴 매칭을 통해서 더욱 복잡한 조건을 형성할 수 있어 유용함. + +```dart +void switcher(dynamic anything) { + switch (anything) { + // 정확히 'aaa' 문자열만 매칭 + case 'aaa': + print('match: aaa'); + break; + // 정확히 [1, 2] 리스트만 매칭 + case [1, 2]: + print('match [1, 2]'); + break; + // 3개의 값이 들어 있는 리스트를 모두 매칭 + case [_,_,_]: + print('match [_,_,_]'); + break; + // 첫 번째와 두 번째 값에 int가 입력된 리스트를 매칭 + case [int a, int b]: + print('match: [int $a, int $b]'); + break; + // 첫 번째 값에 String, 두 번째 값에 int가 입력된 Record 타입 매칭 + case (String a, int b): + print('match: (String: $a, int: $b)'); + break; + default: + print('no match'); + } +} + +void main() { + switcher('aaa'); + switcher([1, 2]); + switcher([3, 4, 5]); + switcher([6, 7]); + switcher(('roo', 10)); + switcher(8) +} + +// 결괏값: +// match: aaa +// match [1, 2] +// match [_,_,_] +// match: [int 6, int 7] +// match: (String: roo, int: 10) +// no match +``` + +**4.3.3. 엄격한 검사** + +- 엄격한 검사(exhaustiveness checking)는 코드가 입력받을 수 있는 모든 조건을 전부 확인하고 있는지 체크하는 기술. +- 다트 3.0에서는 switch 문에 엄격한 검사가 추가되어 모든 조건을 확인하고 있는지 빌드할 때 확인 가능. + +```dart +void main() { + // val에 입력될 수 있는 값은 true, false, null + bool? val; + + // null 조건을 입력하지 않았기 때문에 + // non exhaustive switch statement 에러 출력 + // null case를 추가하거나 default case를 추가해야 에러가 사라짐. + switch (val) { + case true: + print('true'); + case false: + print('false'); + } +} +``` + +4.3.4. 보호 구문 + +- switch문에는 when 키워드로 보호 구문(guard clause)를 추가할 수 있도록 업데이트 됨. +- when 키워드는 boolean으로 반환할 조건을 각 case문에 추가할 수 있으며, +- when 키워드 뒤에 오는 조건이 true를 반환하지 않으면 case 매치가 안됨. + +```dart +void main() { + (int a, int b) val = (1, -1); + + // default가 출력됨. + // 만약 b 값을 0 이상으로 변경하면, + // 1, _ 를 출력함. + switch (val) { + case (1, _) when val.$2 > 0: + print('1, _'); + break; + default: + print('default'); + } +} +``` + +## 4.4. 클래스 제한자 + +- class modifiers: 다트 3.0에 추가된 클래스 제한자는 base, final, interface, sealed, mixin +- 모든 클래스 제한자는 class 키워드 앞에 명시함. +- 클래스 제한자를 명시한 클래스는 해당 클래스를 사용하는 파일이 아닌 다른 파일에 선언해야 정상으로 기능이 작동함. + +**4.4.1 base 제한자** + +- base 제한자는 base 클래스의 기능을 강제하는 제한자. +- base 키워드를 사용하게 되면 해당 클래스는 오직 상속만 할 수 있게 됨. +- 그리고 base 클래스가 아닌 자식 클래스는 꼭 base, final 또는 sealed 제한자를 함께 사용해줘야 함. + +```dart +// lib/4.4/1_a.dart +base class Parent {} +``` + +```dart +// lib/4.4/1_b.dart +import '1_a.dart'; + +// 인스턴스화 가능 +Parent parent = Parent(); + +// rksmd +base class Child extends Parent {} + +// subtype of base or final is not base final or sealed 에러 출력 +// base / sealed / final 제한자 중 하나가 필요. +class Child2 extends Parent {} + +// subtype of base or final is not base final or sealed 에러 출력 +// base 클래스는 implement가 불가능. +class Child3 implements Parent {} +``` + +**4.4.2. final 제한자** + +- final 제한자를 사용하면 같은 파일에서 상속(extend)과 재정의(implement)를 할 수 있지만 외부 파일에서는 할 수 없음. +- 그리고 final 제한자는 base 제한자의 기능을 모두 포함함. + +```dart +// lib/4.4/2_a.dart +final class Parent {} +``` + +```dart +// lib/4.4/2_b.dart +import '2_a.dart'; + +// 인스턴스화 가능 +Parent parent = Parent(); + +// extend 불가능 +class Child extends Parent {} + +// implement 불가능 +class Child2 implements Parent {} +``` + +**4.4.3. interface 제한자** + +- interface 제한자는 클래스를 외부 파일에서 상속받지 못하고 재정의만 할 수 있도록 제한하는 역할을 함. + +```dart +// lib/4.4/3_a.dart +interface class Parent {} +``` + +```dart +// lib/4.4/3_b.dart +import '3_a.dart'; + +// 인스턴스화 가능 +Parent parent = Parent(); + +// extend 불가능 +class Child1 extends Parent {}; + +// implement 가능 +class Child2 implements Parent {} +``` + +4.4.4. sealed 제한자 + +- sealed 제한자는 sealed 클래스를 파일 외부에서 상속, 재정의 그래고 인스턴스화 할 수 없도록 제한함. + +```dart +// lib/4.4/4_a.dart +sealed class Parent{} +``` + +```dart +import '4_a.dart'; + +// 인스턴스화 불가능 +Parent parent = Parent(); + +// extend 불가능 +class Child1 extends Parent {} + +// implements 불가능 +class Child2 implements Parent {} +``` + +**4.4.5. mixin 제한자** + +- 다트 3.0부터는 mixin을 클래스에 사용할 수 있게 됨. +- 일반 mixin과 같은 역할을 하면서도 상속할 수 있다는 장점. + +```dart +// lib/4.4/5.dart +mixin class MixinExample {} + +// extend 가능 +class Child1 extends MixinExample {} + +// mixin으로 사용 가능 +class Child2 with MixinExample {} +``` + +### 핵심 요약 + +1. 레코드: 새로운 타입으로 named parameter와 positional parameter 사용해서 생성 가능 +2. 구조 분해: 타입 내부의 각각의 값을 직접 추출해오는 문법 +3. switch 문: 표현식, 패턴 매칭, 완전 확인, 가드 절이 추가되어 다양한 방법으로 조건을 확인할 수 있음. +4. 클래스 제한자**:** 객체지향 프로그래밍 언어의 특징 중 하나인 클래스의 고유성을 위해 다양한 클래스 제한자가 추가됨.