Ce face generics
Generics (tipuri generice) îți permit să scrii o clasă sau o funcție o singură dată și s-o folosești cu mai multe tipuri. List<String> și List<int> folosesc aceeași clasă List<E>, dar analizorul știe exact ce conține fiecare și oprește note.add('zece').
Parametrul de tip se scrie între < >, de obicei cu o literă mare: T, E (element), K, V (cheie, valoare). Cu T extends num îl restrângi: atunci în cod poți folosi metodele lui num pe valori de tip T.
În Dart generics sunt păstrate la rulare (reified): lista is List<int> chiar verifică tipul elementelor declarat. Dacă nu scrii tipul, Dart îl deduce: var orase = ['Iași']; este List<String>.
Exemple
Exemplul 1: O clasă generică
Pereche<A, B> ține două valori de orice tipuri; tipurile sunt deduse din argumente.
class Pereche<A, B> {
final A prima;
final B aDoua;
Pereche(this.prima, this.aDoua);
Pereche<B, A> inversata() => Pereche(aDoua, prima);
@override
String toString() => '($prima, $aDoua)';
}
void main() {
final p = Pereche('Ana', 10);
print(p);
print(p.inversata());
print(p.runtimeType);
print(Pereche<String, double>('Cluj', 4.5).runtimeType);
}
Rezultat
(Ana, 10)
(10, Ana)
Pereche<String, int>
Pereche<String, double>
Exemplul 2: Funcții generice și restricții
maxim merge pentru orice tip comparabil; suma cere numere (T extends num).
T maxim<T extends Comparable<T>>(List<T> valori) {
var cel = valori.first;
for (final v in valori) {
if (v.compareTo(cel) > 0) cel = v;
}
return cel;
}
num suma<T extends num>(List<T> valori) => valori.fold<num>(0, (s, v) => s + v);
void main() {
print(maxim([7, 10, 9]));
print(maxim(['Brașov', 'Arad', 'Suceava']));
print(suma([1.5, 2.5, 3]));
print(suma<int>([4, 5, 6]));
}
Rezultat
10
Suceava
7.0
15
Exemplul 3: Tipuri păstrate la rulare
O listă goală declarată <int> rămâne List<int> și refuză alte valori chiar și prin dynamic.
void main() {
final note = <int>[];
final Object o = note;
print(o is List<int>);
print(o is List<String>);
final dynamic d = note;
try {
d.add('zece');
} on TypeError {
print('Nu pot adăuga un text într-o List<int>.');
}
}
Rezultat
true
false
Nu pot adăuga un text într-o List<int>.
Greșeli frecvente
- Liste fără tip,
[], pe care le umpli mai târziu: devinList<dynamic>. Scrie<String>[]. - Folosirea metodelor lui
numpe unTfără restricție: eroare. AdaugăT extends num. - Să crezi că
List<int>este subtip al luiList<num>„în siguranță”: Dart permite atribuirea (covarianță), dar adăugarea unuidoubleeșuează la rulare.
Comenzi înrudite
typedef: Dă un nume (alias) unui tip, de obicei unui tip de funcție sau unui tip generic lung.class: Definește un tip nou de obiect, cu câmpuri (date) și metode (comportament).covariant: Permite unei metode suprascrise să ceară un parametru de un tip mai restrâns decât în clasa părinte.records: Grupuri de valori anonime și imutabile, de forma (a, b) sau (nume: a), ideale pentru a întoarce mai multe valori.