dart 3.0

topics 500-모바일개발 503 Dart
types 이론 레퍼런스
tags
references velog.io/@s_soo100/Flutter-Dart-3.0-P... dart.dev/language/patterns

Dart 3.0의 주요 신기능 정리

Records

여러 값을 하나로 묶어서 반환할 수 있다.

// 이전 방식 - 클래스 필요
class Result {
  final int x;
  final int y;
  Result(this.x, this.y);
}

// Dart 3.0 - Record
(int, int) getCoordinates() {
  return (10, 20);
}

// 사용
final coords = getCoordinates();
print(coords.$1);  // 10
print(coords.$2);  // 20

Named Records

({int x, int y}) getCoordinates() {
  return (x: 10, y: 20);
}

final coords = getCoordinates();
print(coords.x);  // 10
print(coords.y);  // 20

왜 Records를 쓸까: 간단한 데이터 묶음을 위해 매번 클래스 만들기 귀찮다. tuple처럼 가볍게 쓸 수 있다.

Patterns (패턴 매칭)

switch 문 강화

// 이전
switch (value) {
  case 1:
    print('one');
    break;
  case 2:
    print('two');
    break;
}

// Dart 3.0 - 표현식으로 사용 가능
final result = switch (value) {
  1 => 'one',
  2 => 'two',
  _ => 'other',
};

Destructuring

final (x, y) = getCoordinates();
print('$x, $y');

// Map
final {'name': name, 'age': age} = {'name': 'John', 'age': 30};

// List
final [first, second, ...rest] = [1, 2, 3, 4, 5];

if-case

final json = {'name': 'John', 'age': 30};

if (json case {'name': String name, 'age': int age}) {
  print('$name is $age years old');
}

왜 패턴 매칭이 좋냐면: null 체크, 타입 체크, 값 추출을 한번에 할 수 있다. 코드가 훨씬 간결해진다.

Sealed Class

상속 가능한 클래스를 제한한다. 같은 파일 내에서만 상속 가능하다.

sealed class Shape {}

class Circle extends Shape {
  final double radius;
  Circle(this.radius);
}

class Rectangle extends Shape {
  final double width;
  final double height;
  Rectangle(this.width, this.height);
}

Exhaustive Switch

sealed class와 switch를 함께 쓰면, 모든 케이스를 처리했는지 컴파일러가 확인해준다.

String describe(Shape shape) {
  return switch (shape) {
    Circle(radius: var r) => 'Circle with radius $r',
    Rectangle(width: var w, height: var h) => 'Rectangle ${w}x${h}',
  };
  // 모든 케이스 처리 안 하면 컴파일 에러
}

왜 sealed를 쓸까: enum처럼 제한된 타입들을 정의하면서, 각 타입에 다른 데이터를 가질 수 있다. 상태 관리에서 유용하다.

Class Modifiers

// final - 상속 불가
final class Config {}

// base - 같은 라이브러리에서만 상속 가능
base class Base {}

// interface - implement만 가능
interface class Interface {}

// sealed - 같은 파일에서만 상속 가능
sealed class Sealed {}

// mixin - 믹스인으로만 사용
mixin class MyMixin {}

실제 활용 예시

API 응답 처리

sealed class ApiResult<T> {}

class Success<T> extends ApiResult<T> {
  final T data;
  Success(this.data);
}

class Failure<T> extends ApiResult<T> {
  final String message;
  Failure(this.message);
}

class Loading<T> extends ApiResult<T> {}

// 사용
Widget buildUI(ApiResult<User> result) {
  return switch (result) {
    Loading() => CircularProgressIndicator(),
    Failure(message: var msg) => Text('Error: $msg'),
    Success(data: var user) => Text('Hello, ${user.name}'),
  };
}

관련 문서