← Назад к вопросам

Что используешь из нововведений в Dart 3.0?

2.3 Middle🔥 171 комментариев
#Dart

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Нововведения Dart 3.0 в практике

Основные фичи Dart 3.0

Дарт 3.0 принёс значительные улучшения в язык. Я активно использую несколько ключевых нововведений в своих проектах.

1. Records и Pattern Matching

Это мощная фича для работы со сложными данными структурами.

Records — неименованные кортежи с типизацией:

// Вместо отдельного класса или Tuple
Record myData = (int: 42, String: 'Hello', bool: true);

// С типизацией
(int, String, bool) data = (10, 'World', false);

// Доступ к полям
print(data.$1); // 10
print(data.$2); // 'World'

// Именованные поля в records
({int age, String name, bool active}) person = (
  age: 25,
  name: 'John',
  active: true,
);

print(person.age);    // 25
print(person.name);   // 'John'

Pattern Matching — мощная деструктуризация:

// Вместо множества if/else
void processUser((int id, String name, String email) user) {
  final (id, name, email) = user;
  print('User $id: $name ($email)');
}

// В switch statements
switch (user) {
  case (int id, String name, _):
    print('Valid user: $name');
  case (_, _, String email) when email.contains('@'):
    print('Valid email: $email');
  default:
    print('Invalid user data');
}

// В функциях с guard clauses
String getUserStatus((int age, String name) person) => switch (person) {
  (var age, var name) when age >= 18 => '$name is an adult',
  (var age, var name) => '$name is a minor',
};

2. Sealed Classes — безопасные иерархии

Отличная замена для type-safe перечисления статусов и событий.

// Определяем sealed класс
sealed class ApiResponse {
  const ApiResponse();
}

// Подклассы — единственный способ расширить
class Success extends ApiResponse {
  final dynamic data;
  Success(this.data);
}

class Error extends ApiResponse {
  final String message;
  Error(this.message);
}

class Loading extends ApiResponse {
  const Loading();
}

// Компилятор проверит, что мы обработали ВСЕ случаи
String handleResponse(ApiResponse response) => switch (response) {
  Success(:final data) => 'Success: $data',
  Error(:final message) => 'Error: $message',
  Loading() => 'Loading...',
  // Если забыть case — ошибка компиляции!
};

3. Enhanced Enums с членами

enum DatabaseOperation {
  create('INSERT'),
  read('SELECT'),
  update('UPDATE'),
  delete('DELETE');
  
  final String sql;
  
  const DatabaseOperation(this.sql);
  
  String toQuery(String table) => '$sql FROM $table';
}

// Использование
print(DatabaseOperation.create.sql);       // 'INSERT'
print(DatabaseOperation.read.toQuery('users')); // 'SELECT FROM users'

4. Extension Types — zero-cost абстракции

Лёгкие обёртки над типами без оверхеда.

// Создаём type-safe обёртку над String для ID
extension type UserId(String value) {
  bool get isValid => value.isNotEmpty && value.length > 5;
  
  String toUpperCase() => value.toUpperCase();
}

// Использование
final id = UserId('abc123def');
if (id.isValid) {
  print(id.toUpperCase()); // ABC123DEF
}

// Предотвращает случайное перепутывание ID типов
void processUser(UserId userId) {
  // Принимает только UserId, не просто String
}

final stringId = 'some-id';
processUser(stringId); // ❌ Ошибка компиляции!
processUser(UserId(stringId)); // ✅ OK

5. Augmentation (Preview) — метапрограммирование

Для код-генерации и AOP без полной зависимости от build_runner в некоторых случаях.

// В файле model.dart
class User {
  final String name;
  final int age;
  
  User(this.name, this.age);
}

// В файле model.augment.dart
augment library 'model.dart';

augment class User {
  @override
  String toString() => 'User(name: $name, age: $age)';
  
  bool get isAdult => age >= 18;
}

Практическое применение в приложении

// Объединяем несколько фич для надёжного обработчика данных
sealed class ApiResult<T> {
  const ApiResult();
}

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

final class ApiError<T> extends ApiResult<T> {
  final String message;
  final int? statusCode;
  const ApiError(this.message, {this.statusCode});
}

final class ApiLoading<T> extends ApiResult<T> {
  const ApiLoading();
}

// Использование с pattern matching
Widget buildApiWidget(ApiResult<List<User>> result) {
  return switch (result) {
    ApiSuccess(:final data) => UserListView(users: data),
    ApiError(:final message, :final statusCode) => ErrorView(
      message: message,
      statusCode: statusCode,
    ),
    ApiLoading() => const LoadingSpinner(),
  };
}

// Type-safe repository
extension type UserId(String value) {
  bool get isValid => value.isNotEmpty;
}

extension type SessionToken(String value) {}

class AuthRepository {
  Future<ApiResult<SessionToken>> login(String email, String password) async {
    try {
      // логика
      return ApiSuccess(SessionToken(token));
    } catch (e) {
      return ApiError('Login failed', statusCode: 401);
    }
  }
}

Почему это важно

Преимущества Dart 3.0 фич:

  • Type Safety — компилятор ловит больше ошибок на этапе компиляции
  • Readability — код с patterns намного понятнее множества if/else
  • Productivity — меньше boilerplate, больше фокуса на логике
  • Performance — extension types имеют zero-cost abstraction
  • Refactoring — sealed classes гарантируют, что я обновлю все switch cases

Эти фичи делают Dart более выразительным языком и позволяют писать более надёжный, читаемый код.

Что используешь из нововведений в Dart 3.0? | PrepBro