Menu
Coddy logo textTech

Vincoli sui generici

Fa parte della sezione Programmazione orientata agli oggetti del percorso Dart di Coddy. Lezione 67 di 110.

A volte hai bisogno che un tipo generico abbia determinate capacità. Per esempio, se vuoi confrontare elementi o accedere a proprietà specifiche, un T senza restrizioni non garantisce che tali funzionalità siano disponibili. I vincoli generici ti permettono di limitare i parametri di tipo a tipi specifici o alle loro sottoclassi.

Usa la parola chiave extends per vincolare un parametro di tipo:

class NumberBox<T extends num> {
  T value;
  
  NumberBox(this.value);
  
  T doubled() => (value * 2) as T;
}

void main() {
  var intBox = NumberBox<int>(5);
  var doubleBox = NumberBox<double>(3.5);
  
  print(intBox.doubled());    // 10
  print(doubleBox.doubled()); // 7.0
  
  // var stringBox = NumberBox<String>('hi');  // Errore!
}

Poiché T extends num, il compilatore sa che value supporta operazioni numeriche come la moltiplicazione. Senza questo vincolo, la chiamata value * 2 non funzionerebbe.

I vincoli funzionano anche con le tue gerarchie di classi:

abstract class Animal {
  String get name;
}

class Dog extends Animal {
  String get name => 'Dog';
}

class Shelter<T extends Animal> {
  List<T> animals = [];
  
  void add(T animal) => animals.add(animal);
  
  void printNames() {
    for (var animal in animals) {
      print(animal.name);  // Sicuro: T garantisce che 'name' esista
    }
  }
}

I vincoli generici combinano la flessibilità dei generics con la sicurezza di sapere quali operazioni sono disponibili sul tuo tipo.

challenge icon

Sfida

Facile

Costruiamo un calcolatore di statistiche che funziona solo con tipi numerici! Creerai una classe generica con un vincolo che ne garantisce l'utilizzo solo con i numeri, permettendoti di eseguire in sicurezza operazioni matematiche sui valori memorizzati.

Organizzerai il codice in due file:

  • stats.dart: crea una classe generica Stats<T extends num> che gestisce un elenco di valori numerici:
    • Una List<T> chiamata values per memorizzare i numeri
    • Un costruttore che inizializza l'elenco con i valori forniti
    • Un metodo sum() che restituisce la somma di tutti i valori come num
    • Un metodo min() che restituisce il valore più piccolo come T
    • Un metodo max() che restituisce il valore più grande come T
    • Un metodo printStats() che mostra le statistiche in un formato ordinato
  • main.dart: importa il file delle statistiche e mostra la classe generica vincolata con diversi tipi numerici:
    • Crea un Stats<int> con i valori [10, 25, 5, 30, 15] e chiama printStats()
    • Stampa una riga vuota
    • Crea un Stats<double> con i valori [3.5, 1.2, 4.8, 2.1] e chiama printStats()

Il metodo printStats() dovrebbe produrre tre righe che mostrano la somma, il valore minimo e quello massimo. Poiché T extends num, puoi usare in sicurezza gli operatori di confronto e le operazioni aritmetiche sui valori: qualcosa che non sarebbe possibile con un tipo generico senza vincoli.

Output previsto:

Sum: 85
Min: 5
Max: 30

Sum: 11.6
Min: 1.2
Max: 4.8

Provalo tu

import 'stats.dart';

void main() {
  // TODO: Crea un Stats<int> con i valori [10, 25, 5, 30, 15]
  // e chiama printStats()
  
  // TODO: Stampa una riga vuota
  
  // TODO: Crea un Stats<double> con i valori [3.5, 1.2, 4.8, 2.1]
  // e chiama printStats()
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Dart online