Menu
Coddy logo textTech

Записи (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
}

Записи автоматически поддерживают равенство на основе своих значений, что делает их удобными для сравнения без необходимости самостоятельной реализации ==. Используйте записи, когда вам нужны простые неизменяемые группы данных; используйте классы, когда вам нужны методы, изменяемость или более сложное поведение.

challenge icon

Задание

Легко

Давайте создадим систему координат, используя записи (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]
}
quiz iconПроверьте себя

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

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