Records (Dart 3)
Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 86 de 110.
Dart 3 introdujo los records: una forma ligera de agrupar múltiples valores sin necesidad de crear una clase completa. Los records son inmutables, tienen igualdad incorporada y son perfectos para devolver múltiples valores desde una función o agrupar datos relacionados de forma temporal.
Crea un registro envolviendo los valores entre paréntesis:
void main() {
// Un registro simple con dos valores
var point = (10, 20);
print(point.$1); // 10 - accede al primer elemento
print(point.$2); // 20 - accede al segundo elemento
// Registros con campos con nombre
var person = (name: 'Alice', age: 30);
print(person.name); // Alice
print(person.age); // 30
}Se accede a los campos posicionales con $1, $2, etc., mientras que los campos con nombre utilizan sus nombres directamente. Puedes mezclar ambos estilos en un solo registro.
Los registros destacan al devolver múltiples valores desde funciones; no es necesario crear una clase solo para devolver dos fragmentos de datos:
(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 residuo 2
var (name, age) = getUser();
print('$name is $age'); // Bob is 25
}Los registros admiten automáticamente la igualdad basada en sus valores, lo que los hace convenientes para realizar comparaciones sin tener que implementar == por tu cuenta. Usa registros cuando necesites agrupaciones de datos simples e inmutables; usa clases cuando necesites métodos, mutabilidad o un comportamiento más complejo.
Desafío
Fácil¡Vamos a construir un sistema de coordenadas usando records! Crearás funciones que trabajen con puntos 2D representados como records, demostrando cómo los records facilitan devolver y trabajar con múltiples valores relacionados sin necesidad de crear clases completas.
Organizarás tu código en dos archivos:
geometry.dart: Crea funciones que utilicen records para trabajar con datos de coordenadas:- Una función
createPoint(int x, int y)que devuelva un record con campos nombradosxey. El tipo de retorno debe ser({int x, int y}) - Una función
midpoint(({int x, int y}) p1, ({int x, int y}) p2)que calcule y devuelva el punto medio entre dos puntos como un record con campos nombrados. Usa la división entera (~/) para el cálculo - Una función
distance(({int x, int y}) p1, ({int x, int y}) p2)que devuelva un record con campos posicionales: la distancia horizontal (diferencia en x) y la distancia vertical (diferencia en y). El tipo de retorno debe ser(int, int). Calcúlalo comop2.x - p1.xyp2.y - p1.y
- Una función
main.dart: Importa tu archivo de geometría y demuestra los records en acción:- Crea dos puntos usando
createPoint: el punto A en(2, 4)y el punto B en(10, 8) - Imprime
'Point A: (${pointA.x}, ${pointA.y})'usando los campos nombrados - Imprime
'Point B: (${pointB.x}, ${pointB.y})'usando los campos nombrados - Calcula el punto medio e imprime
'Midpoint: (${mid.x}, ${mid.y})' - Calcula la distancia y usa la desestructuración para extraer los valores en las variables
dxydy, luego imprime'Distance: dx=$dx, dy=$dy'
- Crea dos puntos usando
¡Observa cómo los records te permiten devolver múltiples valores de forma limpia: campos nombrados para mayor claridad cuando el significado importa, y campos posicionales cuando el contexto es obvio!
Salida esperada:
Point A: (2, 4)
Point B: (10, 8)
Midpoint: (6, 6)
Distance: dx=8, dy=4Hoja de referencia
Dart 3 introdujo los records (registros): una forma ligera de agrupar múltiples valores sin crear una clase completa. Los records son inmutables y perfectos para devolver múltiples valores desde una función.
Crea un record envolviendo los valores entre paréntesis:
// Record simple con campos posicionales
var point = (10, 20);
print(point.$1); // 10 - accede al primer elemento
print(point.$2); // 20 - accede al segundo elemento
// Records con campos con nombre
var person = (name: 'Alice', age: 30);
print(person.name); // Alice
print(person.age); // 30Se accede a los campos posicionales con $1, $2, etc., mientras que los campos con nombre utilizan sus nombres directamente.
Los records son ideales para devolver múltiples valores desde funciones:
// El tipo de retorno especifica la estructura del record
(int, int) divideWithRemainder(int a, int b) {
return (a ~/ b, a % b);
}
// Campos con nombre en el tipo de retorno
(String name, int age) getUser() {
return ('Bob', 25);
}
// Desestructuración de records
var (quotient, remainder) = divideWithRemainder(17, 5);
print('$quotient remainder $remainder'); // 3 remainder 2
var (name, age) = getUser();
print('$name is $age'); // Bob is 25Los tipos de retorno de record con campos con nombre utilizan llaves:
({int x, int y}) createPoint(int x, int y) {
return (x: x, y: y);
}Los records admiten automáticamente la igualdad basada en sus valores.
Pruébalo tú mismo
import 'geometry.dart';
void main() {
// TODO: Crear el punto A en (2, 4) usando createPoint
// TODO: Crear el punto B en (10, 8) usando createPoint
// TODO: Imprimir el Punto A usando campos con nombre: Point A: ([x], [y])
// TODO: Imprimir el Punto B usando campos con nombre: Point B: ([x], [y])
// TODO: Calcular el punto medio e imprimir: Midpoint: ([x], [y])
// TODO: Calcular la distancia y usar la desestructuración para extraer en dx y dy
// Luego imprimir: Distance: dx=[dx], dy=[dy]
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de POO
Archivos externosLibrerías e importacionesIntroducción a la POOClases vs. ObjetosLa palabra clave thisMétodosVariables de instanciaConceptos básicos de constructoresResumen - Calculadora sencilla4Seguridad de nulos
Introducción a la seguridad de nulosNulables vs No nulablesLos operadores ? y !Palabra clave Late y Null SafetyOperadores Null-awareNull Safety en clasesResumen - Sistema de perfil de usuario7Clases abstractas e interfaces
Clases abstractasMétodos abstractosInterfaces en DartInterfaces implícitasImplementar vs. ExtenderInterfaces múltiplesRepaso - Calculadora de figuras10Colecciones y Genéricos
Visión general de List, Set y MapColecciones con seguridad de tiposClases genéricasMétodos genéricosRestricciones genéricasIterable e IteratorResumen - Almacenamiento genérico13Conceptos avanzados de POO
Composición vs. HerenciaMétodos de extensiónClases invocablesClases selladas (Dart 3)Records (Dart 3)Patrones y coincidencia (3.0)Enums con métodos2Constructores en Dart
Constructor por defectoConstructores nombradosListas de inicializaciónConstructores constantesConstructores de fábricaConstructores de redireccionamientoResumen - Constructor de formas5Encapsulamiento
Miembros públicos vs. privadosLa convención del prefijo _Privacidad a nivel de libreríaProfundidad en Getters y SettersOcultamiento de informaciónResumen - Registros de estudiantes8Mixins
Introducción a los MixinsCreación de MixinsUso de múltiples MixinsPalabra clave on en MixinsMixin vs HerenciaMixin vs InterfazResumen - Sistema Animal11Métodos especiales
Sobrescritura de toString()Sobrescritura de hashCode y ==Interfaz ComparableMétodo call()Sobrescritura de noSuchMethodResumen - Colección personalizada14Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy3Propiedades de clase
Miembros de instancia vs. estáticosCampos Final y ConstVariables LateMétodos y campos estáticosGetters y SettersResumen - Gestor de cuentas bancarias6Herencia
Herencia básicaLa palabra clave superSobrescritura de métodosLa anotación @overrideLa palabra clave final en clasesConstructores y herenciaResumen - Jerarquía de empleados9Polimorfismo
Fundamentos del polimorfismoPolimorfismo mediante interfacesComprobación de tipos en tiempo de ejecuciónLos operadores is y asPalabra clave covariantResumen - Procesador de pagos12POO Asíncrona
Futures y async/awaitFundamentos de StreamsStream ControllersConstructores asíncronosAsincronía en métodos de claseRepaso - Data Fetcher15Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository