cascade (..) în Dart

Construirea colecțiilor și a textelor Dart 1.0 (?.. din Dart 2.12)

Operatorul .. face mai multe operații pe același obiect, una după alta, fără să repeți numele lui.

Sintaxă
obiect
  ..metoda1()
  ..camp = valoare
  ..metoda2();          // rezultatul expresiei este obiectul

obiectPosibilNull?..metoda()..alta();

Ce face cascade (..)

Cascada .. apelează o metodă sau setează un câmp pe un obiect, dar, spre deosebire de ., rezultatul expresiei este obiectul însuși, nu ce întoarce metoda. Astfel poți înlănțui mai multe operații: lista..add(1)..add(2)..sort().

Este foarte folosită la construirea obiectelor: creezi obiectul și îl configurezi în aceeași expresie, pe care o poți atribui direct unei variabile final.

?.. (null-aware) face cascada doar dacă obiectul nu este null; se scrie doar la prima operație: obiect?..a()..b().

Exemple

Exemplul 1: Construirea unei liste

add întoarce void, dar cu .. rezultatul este lista, deci operațiile se pot lega.

void main() {
  final orase = <String>[]
    ..add('Suceava')
    ..add('Arad')
    ..addAll(['Bacău', 'Deva'])
    ..sort();
  print(orase);
}

Rezultat

[Arad, Bacău, Deva, Suceava]

Exemplul 2: Configurarea unui obiect

Câmpurile se setează unul după altul pe același obiect.

class Comanda {
  String client = '';
  String adresa = '';
  final List<String> produse = [];
  bool urgenta = false;

  @override
  String toString() => '$client, $adresa: $produse${urgenta ? ' (URGENT)' : ''}';
}

void main() {
  final c = Comanda()
    ..client = 'Larisa Ionescu'
    ..adresa = 'Str. Lungă 10, Brașov'
    ..produse.add('Laptop')
    ..produse.add('Mouse')
    ..urgenta = true;
  print(c);
}

Rezultat

Larisa Ionescu, Str. Lungă 10, Brașov: [Laptop, Mouse] (URGENT)

Exemplul 3: StringBuffer și cascada null-aware

Un tipar des întâlnit cu StringBuffer; apoi ?.. sare peste un obiect null.

StringBuffer? jurnal(bool activ) => activ ? StringBuffer() : null;

void main() {
  final bon = StringBuffer()
    ..writeln('BON FISCAL')
    ..writeln('Cafea      24,50')
    ..writeln('Croissant   8,75')
    ..write('TOTAL      33,25');
  print(bon);

  for (final activ in [true, false]) {
    final j = jurnal(activ)
      ?..write('pornit')
      ..write(', gata');
    print('Jurnal: $j');
  }
}

Rezultat

BON FISCAL
Cafea      24,50
Croissant   8,75
TOTAL      33,25
Jurnal: pornit, gata
Jurnal: null

Greșeli frecvente

  • final l = []..add(1).add(2);: după primul .., .add(2) se aplică rezultatului lui add(1) (care este void). Scrie ..add(2).
  • Cascadă pe o metodă care întoarce un obiect nou (ex. text..toUpperCase()): rezultatul este ignorat, iar text rămâne neschimbat.
  • ?.. pus la fiecare operație: este suficient la prima.

Comenzi înrudite

  • ?. și ?..: Accesul condiționat: ?. apelează o metodă doar dacă obiectul nu este null, altfel dă null.
  • this: Referință la obiectul curent, în interiorul metodelor și constructorilor unei clase.
  • spread (...): Operatorul … pune toate elementele unei colecții în interiorul altei liste, set sau map.
  • collection if și for: if și for direct în interiorul unei liste, set sau map, pentru a construi colecția dintr-o singură expresie.