Записи (Dart 3)
Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy — урок 86 из 110.
В Dart 3 появились записи (records) — это легковесный способ объединения нескольких значений без создания полноценного класса. Записи неизменяемы, обладают встроенной поддержкой равенства и идеально подходят для возврата нескольких значений из функции или временной группировки связанных данных.
Создайте запись, заключив значения в круглые скобки:
void main() {
// A simple record with two values
var point = (10, 20);
print(point.$1); // 10 - access first element
print(point.$2); // 20 - access second element
// Records with named fields
var person = (name: 'Alice', age: 30);
print(person.name); // Alice
print(person.age); // 30
}Доступ к позиционным полям осуществляется с помощью $1, $2 и т. д., в то время как именованные поля используют свои имена напрямую. Вы можете смешивать оба стиля в одной записи.
Записи (Records) отлично подходят для возврата нескольких значений из функций — нет необходимости создавать класс только для того, чтобы вернуть два фрагмента данных:
(int, int) divideWithRemainder(int a, int b) {
return (a ~/ b, a % b);
}
(String name, int age) getUser() {
return ('Bob', 25);
}
void main() {
var (quotient, remainder) = divideWithRemainder(17, 5);
print('$quotient remainder $remainder'); // 3 остаток 2
var (name, age) = getUser();
print('$name is $age'); // Bob — 25
}Записи автоматически поддерживают равенство на основе своих значений, что делает их удобными для сравнения без необходимости самостоятельной реализации ==. Используйте записи, когда вам нужны простые неизменяемые группы данных; используйте классы, когда вам нужны методы, изменяемость или более сложное поведение.
Задание
ЛегкоДавайте создадим систему координат, используя записи (records)! Вы создадите функции для работы с 2D-точками, представленными в виде записей, что продемонстрирует, как легко записи позволяют возвращать и обрабатывать несколько связанных значений без создания полноценных классов.
Вы организуете свой код в двух файлах:
geometry.dart: Создайте функции, использующие записи для работы с координатными данными:- Функция
createPoint(int x, int y), которая возвращает запись с именованными полямиxиy. Тип возвращаемого значения должен быть({int x, int y}) - Функция
midpoint(({int x, int y}) p1, ({int x, int y}) p2), которая вычисляет и возвращает среднюю точку между двумя точками в виде записи с именованными полями. Используйте целочисленное деление (~/) для вычислений - Функция
distance(({int x, int y}) p1, ({int x, int y}) p2), которая возвращает запись с позиционными полями: горизонтальное расстояние (разница по x) и вертикальное расстояние (разница по y). Тип возвращаемого значения должен быть(int, int). Вычисляйте какp2.x - p1.xиp2.y - p1.y
- Функция
main.dart: Импортируйте ваш файл геометрии и продемонстрируйте работу записей:- Создайте две точки с помощью
createPoint: точку A в(2, 4)и точку B в(10, 8) - Выведите
'Point A: ([x], [y])', используя именованные поля - Выведите
'Point B: ([x], [y])', используя именованные поля - Вычислите среднюю точку и выведите
'Midpoint: ([x], [y])' - Вычислите расстояние и используйте деструктуризацию для извлечения значений в переменные
dxиdy, затем выведите'Distance: dx=[dx], dy=[dy]'
- Создайте две точки с помощью
Обратите внимание, как записи позволяют изящно возвращать несколько значений — именованные поля для ясности, когда важен смысл, и позиционные поля, когда контекст очевиден!
Ожидаемый вывод:
Point A: (2, 4)
Point B: (10, 8)
Midpoint: (6, 6)
Distance: dx=8, dy=4Шпаргалка
Dart 3 представил записи (records) — легковесный способ объединения нескольких значений без создания полноценного класса. Записи неизменяемы и идеально подходят для возврата нескольких значений из функции.
Создайте запись, заключив значения в круглые скобки:
// Простая запись с позиционными полями
var point = (10, 20);
print(point.$1); // 10 - доступ к первому элементу
print(point.$2); // 20 - доступ ко второму элементу
// Записи с именованными полями
var person = (name: 'Alice', age: 30);
print(person.name); // Alice
print(person.age); // 30Доступ к позиционным полям осуществляется через $1, $2 и т. д., в то время как именованные поля используют свои имена напрямую.
Записи идеально подходят для возврата нескольких значений из функций:
// Тип возвращаемого значения определяет структуру записи
(int, int) divideWithRemainder(int a, int b) {
return (a ~/ b, a % b);
}
// Именованные поля в типе возвращаемого значения
(String name, int age) getUser() {
return ('Bob', 25);
}
// Деструктуризация записей
var (quotient, remainder) = divideWithRemainder(17, 5);
print('$quotient remainder $remainder'); // 3 remainder 2
var (name, age) = getUser();
print('$name is $age'); // Bob is 25Типы возвращаемых записей с именованными полями используют фигурные скобки:
({int x, int y}) createPoint(int x, int y) {
return (x: x, y: y);
}Записи автоматически поддерживают сравнение на равенство на основе их значений.
Попробуйте сами
import 'geometry.dart';
void main() {
// TODO: Создайте точку A в (2, 4), используя createPoint
// TODO: Создайте точку B в (10, 8), используя createPoint
// TODO: Выведите точку A, используя именованные поля: Point A: ([x], [y])
// TODO: Выведите точку B, используя именованные поля: Point B: ([x], [y])
// TODO: Вычислите координаты середины отрезка и выведите: Midpoint: ([x], [y])
// TODO: Вычислите расстояние и используйте деструктуризацию для извлечения в dx и dy
// Затем выведите: Distance: dx=[dx], dy=[dy]
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыБиблиотеки и импортВведение в ООПКлассы и объектыКлючевое слово thisМетодыПеременные экземпляраОсновы конструкторовИтоги — Простой калькулятор4Null-безопасность
Введение в Null-безопасностьNullable и Non-Nullable типыОператоры ? и !Ключевое слово Late и Null-безопасностьNull-aware операторыNull-безопасность в классахИтоги — Система профилей пользователей7Абстрактные классы и интерфейсы
Абстрактные классыАбстрактные методыИнтерфейсы в DartНеявные интерфейсыРеализация против наследованияМножественные интерфейсыИтоги — Калькулятор фигур10Коллекции и обобщения
Обзор List, Set, MapТипобезопасные коллекцииОбобщенные классыОбобщенные методыОграничения обобщенийIterable и IteratorИтоги: Обобщенное хранилище13Продвинутые концепции ООП
Композиция против наследованияМетоды расширенияВызываемые классыЗапечатанные классы (Dart 3)Записи (Dart 3)Паттерны и сопоставление (3.0)Перечисления с методами16Проект: Управление библиотекой
Обзор проектаКлассы Book и User2Конструкторы в Dart
Конструктор по умолчаниюИменованные конструкторыСписки инициализацииКонстантные конструкторыФабричные конструкторыПеренаправляющие конструкторыИтоги — Shape Builder5Инкапсуляция
Публичные и приватные членыСоглашение о префиксе _Приватность на уровне библиотекГеттеры и сеттеры: подробный разборСкрытие данныхИтоги — Записи о студентах8Mixins
Введение в MixinsСоздание MixinsИспользование нескольких MixinsКлючевое слово on в MixinsMixin и наследованиеMixin и интерфейсИтоги: Система животных11Специальные методы
Переопределение toString()Переопределение hashCode и ==Интерфейс ComparableМетод call()Переопределение noSuchMethodПовторение — Пользовательская коллекция14Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy3Свойства классов
Члены экземпляра и статические членыПоля Final и ConstПеременные LateСтатические методы и поляГеттеры и сеттерыИтоги — Менеджер банковского счета6Наследование
Основы наследованияКлючевое слово superПереопределение методовАннотация @overrideКлючевое слово final для классовКонструкторы и наследованиеИтоги: Иерархия сотрудников9Полиморфизм
Основы полиморфизмаПолиморфизм через интерфейсыПроверка типов во время выполненияОператоры is и asКлючевое слово covariantИтоги — Обработчик платежей12Асинхронное ООП
Futures и async/awaitОсновы StreamsКонтроллеры StreamАсинхронные конструкторыАсинхронность в методах классовИтоги — Data Fetcher15Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн Репозиторий