Lesson 10 · 10 of 20
Records and destructuring · Dart
Return several values without writing a class using Dart 3 records, and destructure them into variables, in loops and in swaps.

A record groups several values without needing a class. It can have positional fields, like (double, double, double), or named ones, like ({String city, double celsius}). The typedef gives the latter a short name, Reading, which is then used like any other type.
summarize returns three values at once: the minimum, the maximum and the average. In main, final (low, high, avg) = ... destructures them: it is a pattern that unpacks the record into three variables in one go. Before Dart 3 this would have needed a helper class or an untyped list.
In the for loop, the pattern (:city, :celsius) pulls the named fields into variables with the same names; :city is short for city: city. The loop then reads almost like a sentence and only warns about the cities above 30 degrees.
Named fields are read by name (first.city) and positional ones with $1, $2…, which is why summarize([1, 2]).$2 is the maximum, 2.0. Records have value equality: two records with the same fields are == even when created separately. Finally, (a, b) = (b, a) swaps two variables without a temporary one.
Code · 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');}Output · 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
Key points
- A record groups values without a class:
(1, 'a')or(x: 1, y: 2). - Returning a record is the natural way to return several values.
final (a, b) = record;destructures it into variables.:fieldpulls a named field into a variable of the same name.- Records are compared by value.
Exercise
Make summarize return a named record, ({double min, double max, double avg}), and change the destructuring to final (:min, :max, :avg) = ....