Ce face covariant
În mod normal, o metodă suprascrisă trebuie să accepte cel puțin aceleași argumente ca originalul. Dacă Animal.mananca(Hrana h), atunci Pisica.mananca(Peste p) ar fi o eroare, pentru că cineva ar putea da pisicii orice Hrana.
Cu covariant (pus pe parametru, în părinte sau în copil), îi spui analizorului: „știu ce fac, verifică tipul la rulare”. Codul se compilează, iar dacă la rulare primește alt tip, apare un TypeError.
Se folosește rar, în ierarhii unde tipul exact al parametrului depinde de subclasă (de exemplu operator == sau metode de comparare). Când se poate, generics sunt o soluție mai sigură.
Exemple
Exemplul 1: Fiecare animal mănâncă alt fel de hrană
covariant din clasa Animal permite subclaselor să ceară un tip mai precis de hrană.
class Hrana {
final String nume;
Hrana(this.nume);
}
class Peste extends Hrana {
Peste() : super('pește');
}
class Os extends Hrana {
Os() : super('os');
}
class Animal {
void mananca(covariant Hrana h) => print('Animalul mănâncă ${h.nume}.');
}
class Pisica extends Animal {
@override
void mananca(Peste p) => print('Pisica mănâncă ${p.nume}.');
}
class Caine extends Animal {
@override
void mananca(Os o) => print('Câinele roade un ${o.nume}.');
}
void main() {
Pisica().mananca(Peste());
Caine().mananca(Os());
}
Rezultat
Pisica mănâncă pește.
Câinele roade un os.
Exemplul 2: Verificarea de la rulare
Văzută ca Animal, pisica primește un os. Analizorul permite, dar la rulare apare TypeError.
class Hrana {}
class Peste extends Hrana {}
class Os extends Hrana {}
class Animal {
void mananca(covariant Hrana h) => print('mănâncă');
}
class Pisica extends Animal {
@override
void mananca(Peste p) => print('Pisica mănâncă pește.');
}
void main() {
Animal a = Pisica();
a.mananca(Peste());
try {
a.mananca(Os());
} on TypeError {
print('Eroare de tip: pisica nu mănâncă oase.');
}
}
Rezultat
Pisica mănâncă pește.
Eroare de tip: pisica nu mănâncă oase.
Greșeli frecvente
- Restrângerea tipului unui parametru fără
covariant: eroarea'Pisica.mananca' ('void Function(Peste)') isn't a valid override of 'Animal.mananca' ('void Function(Hrana)'). - Să folosești
covariantca să „scapi” de erori de tip: mută doar verificarea la rulare, unde greșeala costă mai mult. - Să uiți că o colecție de tipul părinte poate primi orice subtip: fiecare apel prin tipul părinte poate eșua la rulare.
Comenzi înrudite
extends: Creează o subclasă care moștenește câmpurile și metodele altei clase și le poate înlocui.generics: Clase și funcții cu tipuri ca parametri (<T>), care funcționează la fel pentru orice tip, păstrând verificarea tipurilor.is și is!: Verifică la rulare dacă o valoare are un anumit tip; după verificare, variabila poate fi folosită ca acel tip.