Menu
Coddy logo textTech

Паттерны и сопоставление (3.0)

Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy — урок 87 из 110.

В Dart 3 появилось сопоставление с образцом — мощный способ деструктуризации и проверки данных в одном выражении. Шаблоны позволяют извлекать значения из объектов, проверять их структуру и привязывать переменные — и всё это одновременно.

Вы уже видели базовую деструктуризацию с записями. Шаблоны расширяют это для работы с объектами, списками и картами:

void main() {
  // Шаблоны списков
  var numbers = [1, 2, 3];
  var [a, b, c] = numbers;
  print('$a, $b, $c');  // 1, 2, 3
  
  // Шаблоны карт
  var user = {'name': 'Alice', 'age': 30};
  var {'name': name, 'age': age} = user;
  print('$name is $age');  // Alice is 30
}

Шаблоны становятся особенно мощными в выражениях switch. Вы можете сопоставлять по типу, значению и структуре одновременно:

String describe(Object obj) {
  return switch (obj) {
    int n when n < 0 => 'Negative number',
    int n => 'Positive number: $n',
    String s => 'String of length ${s.length}',
    [int first, ...] => 'List starting with $first',
    _ => 'Something else',
  };
}

void main() {
  print(describe(-5));        // Отрицательное число
  print(describe(42));        // Положительное число: 42
  print(describe([1, 2, 3])); // Список, начинающийся с 1
}

Конструкция when добавляет условия к шаблонам, а ... соответствует оставшимся элементам в списке. Символ подчеркивания _ служит подстановочным знаком, который соответствует чему угодно. В сочетании с изолированными (sealed) классами шаблоны обеспечивают исчерпывающую и типобезопасную обработку сложных структур данных.

challenge icon

Задание

Легко

Давайте создадим классификатор данных, который использует сопоставление с образцом для анализа и категоризации различных типов входных данных! Вы создадите систему, которая может идентифицировать и описывать различные структуры данных, используя мощные возможности сопоставления с образцом в Dart 3.

Вы организуете свой код в два файла:

  • classifier.dart: Создайте функцию с именем classify, которая принимает параметр Object и возвращает описание типа String. Используйте выражение switch с сопоставлением с образцом для обработки следующих случаев:
    • Пустой список [] должен возвращать Empty list
    • Список, содержащий ровно один целочисленный элемент, должен возвращать Single item: [value]
    • Список, содержащий ровно два элемента, должен возвращать Pair: [first] and [second]
    • Список, начинающийся с целого числа, за которым следуют другие элементы, должен возвращать List starting with [first], length: [total length] (используйте rest-паттерн ...)
    • Map, содержащий ключи 'name' и 'age', должен возвращать [name] is [age] years old (используйте деструктуризацию паттерна map)
    • Целое число, которое является отрицательным (используйте предложение when), должно возвращать Negative: [value]
    • Целое число, равное нулю, должно возвращать Zero
    • Любое другое целое число должно возвращать Positive: [value]
    • Любое другое значение должно возвращать Unknown type
  • main.dart: Импортируйте свой классификатор и продемонстрируйте сопоставление с образцом на различных входных данных. Выведите результат классификации каждого из этих значений:
    • Пустой список []
    • Список с одним элементом: [42]
    • Список с двумя элементами: ['hello', 'world']
    • Более длинный список: [1, 2, 3, 4, 5]
    • Map: {'name': 'Alice', 'age': 25}
    • Целое число -10
    • Целое число 0
    • Целое число 99

Эта задача объединяет паттерны списков, паттерны map, предложение when для условий (guards) и rest-паттерн (...) — все ключевые особенности сопоставления с образцом из урока!

Ожидаемый вывод:

Empty list
Single item: 42
Pair: hello and world
List starting with 1, length: 5
Alice is 25 years old
Negative: -10
Zero
Positive: 99

Шпаргалка

В Dart 3 появилось сопоставление с образцом (pattern matching) для деструктуризации и проверки данных в одном выражении.

Образцы списков

Извлечение значений из списков:

var numbers = [1, 2, 3];
var [a, b, c] = numbers;
print('$a, $b, $c');  // 1, 2, 3

Образцы карт (Map)

Деструктуризация карт по ключу:

var user = {'name': 'Alice', 'age': 30};
var {'name': name, 'age': age} = user;
print('$name is $age');  // Alice is 30

Выражения switch с образцами

Сопоставление по типу, значению и структуре:

String describe(Object obj) {
  return switch (obj) {
    int n when n < 0 => 'Negative number',
    int n => 'Positive number: $n',
    String s => 'String of length ${s.length}',
    [int first, ...] => 'List starting with $first',
    _ => 'Something else',
  };
}

Особенности образцов

  • Предложение when: добавляет условия к образцам
  • ... (остаточный образец): соответствует оставшимся элементам в списке
  • _ (подстановочный знак): соответствует чему угодно

Попробуйте сами

import 'classifier.dart';

void main() {
  // TODO: Используйте функцию classify для категоризации каждого значения
  // и выведите результаты
  
  // Тест с пустым списком
  print(classify([]));
  
  // TODO: Протестируйте со списком, содержащим один элемент: [42]
  
  // TODO: Протестируйте со списком, содержащим два элемента: ['hello', 'world']
  
  // TODO: Протестируйте с более длинным списком: [1, 2, 3, 4, 5]
  
  // TODO: Протестируйте с картой (map): {'name': 'Alice', 'age': 25}
  
  // TODO: Протестируйте с целым числом -10
  
  // TODO: Протестируйте с целым числом 0
  
  // TODO: Протестируйте с целым числом 99
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование