get și set în Dart

Proprietăți calculate (get) și proprietăți cu validare la atribuire (set), folosite ca niște câmpuri.

Sintaxă
Tip get nume => expresie;          // getter
set nume(Tip valoare) { ... }      // setter

obiect.nume;            // apelează getter-ul
obiect.nume = valoare;  // apelează setter-ul

Ce face get și set

Un getter este o metodă fără paranteze care se citește ca un câmp: dreptunghi.arie. Valoarea se calculează la fiecare citire, deci este mereu la zi. Un setter se apelează când scrii obiect.nume = valoare și poate verifica sau transforma valoarea.

Fiecare câmp obișnuit are automat un getter și (dacă nu este final) un setter. De aceea poți începe cu un câmp public și, mai târziu, să-l înlocuiești cu getter/setter fără să schimbi codul care îl folosește.

Un tipar frecvent: un câmp privat _valoare și un getter public valoare, fără setter. Din afară, proprietatea se poate citi, dar nu modifica.

Exemple

Exemplul 1: Proprietăți calculate

arie și estePatrat nu sunt stocate: se calculează din laturi la fiecare citire.

class Dreptunghi {
  double latime, inaltime;
  Dreptunghi(this.latime, this.inaltime);

  double get arie => latime * inaltime;
  double get perimetru => 2 * (latime + inaltime);
  bool get estePatrat => latime == inaltime;
}

void main() {
  final camera = Dreptunghi(4, 3.5);
  print('Arie: ${camera.arie} m², perimetru: ${camera.perimetru} m');
  camera.inaltime = 4;
  print('Arie nouă: ${camera.arie} m², pătrat: ${camera.estePatrat}');
}

Rezultat

Arie: 14.0 m², perimetru: 15.0 m
Arie nouă: 16.0 m², pătrat: true

Exemplul 2: Setter cu validare

Nota se poate schimba doar cu o valoare între 1 și 10; altfel se aruncă RangeError.

class Nota {
  final String materie;
  int _valoare;

  Nota(this.materie, this._valoare);

  int get valoare => _valoare;

  set valoare(int noua) {
    if (noua < 1 || noua > 10) {
      throw RangeError.range(noua, 1, 10, 'nota');
    }
    _valoare = noua;
  }
}

void main() {
  final n = Nota('Matematică', 7);
  n.valoare = 9;
  print('${n.materie}: ${n.valoare}');
  try {
    n.valoare = 11;
  } on RangeError catch (e) {
    print('Respins: ${e.message}, valoarea ${e.invalidValue}');
  }
}

Rezultat

Matematică: 9
Respins: Invalid value, valoarea 11

Exemplul 3: Proprietate doar pentru citire

total are doar getter. Lista internă se schimbă doar prin adauga; din afară se primește o copie care nu se poate modifica.

class Cos {
  final List<double> _preturi = [];

  void adauga(double pret) => _preturi.add(pret);

  double get total => _preturi.fold(0, (s, p) => s + p);
  int get numarProduse => _preturi.length;
  List<double> get preturi => List.unmodifiable(_preturi);
}

void main() {
  final cos = Cos()
    ..adauga(12.5)
    ..adauga(30);
  print('${cos.numarProduse} produse, total ${cos.total} lei');
  print(cos.preturi);
}

Rezultat

2 produse, total 42.5 lei
[12.5, 30.0]

Greșeli frecvente

  • Getter scris cu paranteze (double get arie() => ...): eroare, getter-ul nu are listă de parametri.
  • Un setter care se apelează pe sine: set nota(int v) { nota = v; } intră într-o recursivitate infinită. Scrie în câmpul privat _nota.
  • Calcule scumpe într-un getter folosit des: se refac la fiecare citire. Salvează rezultatul dacă datele nu se schimbă.

Comenzi înrudite

  • class: Definește un tip nou de obiect, cu câmpuri (date) și metode (comportament).
  • this: Referință la obiectul curent, în interiorul metodelor și constructorilor unei clase.
  • late: Amână inițializarea unei variabile nenule: valoarea se dă mai târziu sau se calculează la prima folosire.
  • operator: Definește ce fac operatorii (+, -, ==, [], < etc.) pentru obiectele unei clase.