Records și Tupluri Anonime Tipizate în Dart 3: Returnarea Multiplă de Valori și Destructurare Pozițională în Dart

Ghid practic pentru Records în Dart 3: declararea de tupluri tipizate anonime, câmpuri poziționale ($1, $2) și numite, egalitate structurală pe bază de valoare și returnarea valorilor multiple fără clase DTO.

Sintaxă
(int statusCode, {String message, Map<String, dynamic> data}) fetchData() => ...

Până la apariția versiunii Dart 3.0, returnarea mai multor valori dintr-o funcție presupunea fie definirea unei clase DTO de unică folosință, fie folosirea unor structuri neomogene precum List<dynamic> sau Map<String, dynamic>, care sacrificau complet siguranța tipurilor.

Records rezolvă definitiv această problemă: sunt tipuri compuse anonime, imutabile și tipizate static. Ele permit gruparea facilă a valorilor cu sintaxă concisă de paranteze rotunde, suportă atât câmpuri poziționale cât și câmpuri denumite, și implementează automat egalitatea structurală pe bază de valoare (hashCode și ==).

Definirea și Returnarea de Records în Funcții
// Funcție care returnează un Record cu un câmp pozițional și două câmpuri denumite:
(bool isSuccess, {String? errorMessage, int latencyMs}) pingServer(String url) {
  // Simulare verificare rețea:
  if (url.startsWith('https')) {
    return (true, errorMessage: null, latencyMs: 42);
  } else {
    return (false, errorMessage: 'Protocol nesecurizat', latencyMs: 0);
  }
}

void main() {
  final result = pingServer('https://dexblog.ro');

  // Accesare prin proprietăți poziționale ($1) și denumite:
  print('Succes: ${result.$1}');
  print('Latență: ${result.latencyMs} ms');

  // Destructurare directă a rezultatului:
  final (success, :errorMessage, :latencyMs) = pingServer('http://insecure.test');
  if (!success) {
    print('Conexiune eșuată: $errorMessage');
  }
}

Caracteristicile Fundamentale ale Records în Dart

Proprietate Tehnică Comportament în Dart 3 Impact asupra Codului
Imutabilitate Toate câmpurile unui Record sunt strict final la runtime. Garantează absența efectelor secundare și siguranță în medii concurente.
Egalitate Structurală Două Records cu aceleași valori sunt egale: (1, 'a') == (1, 'a') este true. Pot fi utilizate direct ca chei în Map sau elemente în Set fără suprascrierea hashCode.
Cost Zero de Definire Nu necesită fișiere sau clase separate în proiect. Elimină „boilerplate”-ul excesiv asociat claselor de transfer de date (DTO).
Tipizare Completă Compilatorul cunoaște tipul exact al fiecărui element. Auto-completare perfectă în IDE și validare completă la compilare AOT.
Egalitatea pe Bază de Valoare a Records
void main() {
  final pointA = (x: 10, y: 20);
  final pointB = (x: 10, y: 20);
  final pointC = (x: 15, y: 20);

  print(pointA == pointB); // true (aceeași structură și valori!)
  print(pointA == pointC); // false

  // Utilizare ca element într-un Set (elimină duplicatele automat):
  final setOfPoints = {pointA, pointB, pointC};
  print(setOfPoints.length); // 2
}