DMarlon Studio

Lección 10 · 10 de 20

Records y desestructuración · Dart

Devuelva varios valores sin crear clases con los records de Dart 3, y desestructúrelos en variables, en bucles y en intercambios.

Dart · Records y desestructuración en DMarlon Studio: el código del ejemplo y su salida en la terminal

Un record agrupa varios valores sin tener que crear una clase. Puede tener campos posicionales, como (double, double, double), o con nombre, como ({String city, double celsius}). El typedef da a este último un nombre corto, Reading, que después se usa como cualquier otro tipo.

summarize devuelve tres valores a la vez: el mínimo, el máximo y la media. En main, final (low, high, avg) = ... los desestructura: es un patrón que deshace el record en tres variables de una sola vez. Antes de Dart 3 habría hecho falta una clase auxiliar o una lista sin tipos.

En el for, el patrón (:city, :celsius) toma los campos con nombre en variables que se llaman igual; :city es la forma corta de city: city. Así el bucle se lee casi como una frase y solo avisa de las ciudades que pasan de 30 grados.

Los campos con nombre se leen por su nombre (first.city) y los posicionales con $1, $2…; por eso summarize([1, 2]).$2 es el máximo, 2.0. Los records tienen igualdad por valor: dos records con los mismos campos son == aunque se hayan creado por separado. Por último, (a, b) = (b, a) intercambia dos variables sin necesitar una auxiliar.

Código · main.dart

// A record type with named fields, given a short name.typedef Reading = ({String city, double celsius});// Returning a positional record: three values, no helper class.(double, double, double) summarize(List<double> values) {  final sorted = [...values]..sort();  final average = values.reduce((a, b) => a + b) / values.length;  return (sorted.first, sorted.last, average);}void main() {  final List<Reading> readings = [    (city: 'Madrid', celsius: 31.5),    (city: 'Bilbao', celsius: 22.0),    (city: 'Seville', celsius: 36.2),    (city: 'Vigo', celsius: 19.8),  ];  // Destructure the result into three variables at once.  final (low, high, avg) = summarize([for (final r in readings) r.celsius]);  print('Low $low, high $high, average ${avg.toStringAsFixed(1)}');  // :city is short for city: city (take the field into a variable).  for (final (:city, :celsius) in readings) {    if (celsius > 30) print('Heat warning in $city ($celsius C)');  }  final first = readings.first;  print('Fields: ${first.city}, positional: ${summarize([1, 2]).$2}');  print('Equal by value: ${(city: 'Vigo', celsius: 19.8) == readings[3]}');  var (a, b) = ('left', 'right');  (a, b) = (b, a); // swap without a temporary variable  print('Swapped: $a $b');}

Salida · dart run main.dart

Low 19.8, high 36.2, average 27.4
Heat warning in Madrid (31.5 C)
Heat warning in Seville (36.2 C)
Fields: Madrid, positional: 2.0
Equal by value: true
Swapped: right left

Para recordar

  • Un record agrupa valores sin crear una clase: (1, 'a') o (x: 1, y: 2).
  • Devolver un record es la forma natural de devolver varios valores.
  • final (a, b) = record; desestructura en variables.
  • :campo toma un campo con nombre en una variable del mismo nombre.
  • Los records se comparan por valor.

Ejercicio

Haga que summarize devuelva un record con nombre, ({double min, double max, double avg}), y cambie la desestructuración por final (:min, :max, :avg) = ....