extension în Dart

Adaugă metode, getter-e și operatori unui tip existent (chiar și String sau int), fără să-l modifici.

Sintaxă
extension NumeExtensie on Tip {
  TipReturnat metoda() => ...;   // în corp, this este valoarea de tipul Tip
  TipReturnat get proprietate => ...;
}

Ce face extension

O extensie adaugă funcționalitate unui tip pe care nu-l poți schimba: String, int, List sau clase din alte pachete. După extension TextRo on String { ... } poți scrie 'ana'.capitalizat ca și cum metoda ar fi fost acolo de la început.

În corpul extensiei, this (sau simplu numele membrilor) se referă la valoarea pe care este apelată metoda. Extensiile pot avea metode, getter-e, setter-e, operatori și membri static, dar nu câmpuri de instanță.

Extensiile sunt rezolvate după tipul static al variabilei, la compilare. Pe o valoare dynamic nu funcționează. Ca să fie folosită în alt fișier, extensia trebuie să aibă nume și să fie importată.

Exemple

Exemplul 1: Metode noi pentru String

Extensia adaugă un getter și o metodă oricărui String.

extension TextRo on String {
  String get capitalizat => isEmpty ? this : this[0].toUpperCase() + substring(1).toLowerCase();

  String faraDiacritice() {
    const din = 'ăâîșțĂÂÎȘȚ';
    const in_ = 'aaistAAIST';
    return split('').map((c) {
      final i = din.indexOf(c);
      return i == -1 ? c : in_[i];
    }).join();
  }
}

void main() {
  print('bUCUREȘTI'.capitalizat);
  print('Târgu Mureș, Piatra Neamț'.faraDiacritice());
}

Rezultat

București
Targu Mures, Piatra Neamt

Exemplul 2: Extensie pentru numere

lei formatează un num ca preț; funcționează pentru int și double.

extension Pret on num {
  String get lei => '${toStringAsFixed(2).replaceAll('.', ',')} lei';
  num cuReducere(int procent) => this * (100 - procent) / 100;
}

void main() {
  print(49.9.lei);
  print(120.lei);
  print(120.cuReducere(15).lei);
}

Rezultat

49,90 lei
120,00 lei
102,00 lei

Exemplul 3: Extensie generică pe liste

media apare pe orice List de numere, iar alDoilea pe orice listă.

extension Statistici on List<num> {
  double get media => isEmpty ? 0 : fold<double>(0, (s, x) => s + x) / length;
}

extension Elemente<T> on List<T> {
  T? get alDoilea => length > 1 ? this[1] : null;
}

void main() {
  final note = [9, 7, 10, 8];
  print('Media: ${note.media}');
  print(['Ana', 'Bianca'].alDoilea);
  print(<String>['singur'].alDoilea);
}

Rezultat

Media: 8.5
Bianca
null

Greșeli frecvente

  • Apelul unei metode din extensie pe o valoare dynamic: NoSuchMethodError la rulare, pentru că extensiile se aleg după tipul static.
  • Câmpuri de instanță într-o extensie: nu sunt permise (Extensions can't declare instance fields).
  • Două extensii importate cu aceeași metodă pentru același tip: conflict. Ascunde una cu hide sau apelează explicit TextRo('ana').capitalizat.

Comenzi înrudite

  • extension type: Un tip nou, verificat la compilare, care la rulare este doar o valoare existentă (de ex. un int), fără cost.
  • generics: Clase și funcții cu tipuri ca parametri (<T>), care funcționează la fel pentru orice tip, păstrând verificarea tipurilor.
  • operator: Definește ce fac operatorii (+, -, ==, [], < etc.) pentru obiectele unei clase.
  • import: Face disponibile în fișierul curent numele publice ale altei biblioteci: din SDK, dintr-un pachet sau din proiect.