Ograniczenia typów generycznych
Część sekcji Programowanie obiektowe ścieżki Dart w Coddy. Lekcja 67 z 110.
Czasami potrzebujesz, aby typ generyczny miał określone możliwości. Na przykład jeśli chcesz porównywać elementy lub uzyskiwać dostęp do określonych właściwości, nieograniczony typ T nie gwarantuje, że te funkcje będą dostępne. Ograniczenia typów generycznych pozwalają ograniczyć parametry typów do określonych typów lub ich podklas.
Użyj słowa kluczowego extends, aby ograniczyć parametr typu:
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'); // Błąd!
}Ponieważ T extends num, kompilator wie, że value obsługuje operacje numeryczne, takie jak mnożenie. Bez tego ograniczenia wywołanie value * 2 zakończyłoby się błędem.
Ograniczenia działają również z własnymi hierarchiami klas:
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); // Bezpieczne: T gwarantuje, że 'name' istnieje
}
}
}Ograniczenia typów generycznych łączą elastyczność typów generycznych z bezpieczeństwem wynikającym z wiedzy o tym, jakie operacje są dostępne dla danego typu.
Wyzwanie
ŁatwyZbudujmy kalkulator statystyk, który działa tylko z typami liczbowymi! Utworzysz klasę generyczną z ograniczeniem, które zapewnia, że można jej używać tylko z liczbami, dzięki czemu bezpiecznie wykonasz operacje matematyczne na przechowywanych wartościach.
Podzielisz kod na dwa pliki:
stats.dart: Utwórz generyczną klasęStats<T extends num>, która zarządza listą wartości liczbowych:List<T>o nazwievaluesdo przechowywania liczb- Konstruktor, który inicjalizuje listę podanymi wartościami
- Metodę
sum(), która zwraca sumę wszystkich wartości jakonum - Metodę
min(), która zwraca najmniejszą wartość jakoT - Metodę
max(), która zwraca największą wartość jakoT - Metodę
printStats(), która wyświetla statystyki w sformatowanej postaci
main.dart: Zaimportuj plik stats i pokaż działanie ograniczonej klasy generycznej z różnymi typami liczbowymi:- Utwórz
Stats<int>z wartościami[10, 25, 5, 30, 15]i wywołajprintStats() - Wypisz pustą linię
- Utwórz
Stats<double>z wartościami[3.5, 1.2, 4.8, 2.1]i wywołajprintStats()
- Utwórz
Metoda printStats() powinna wyświetlać trzy wiersze z sumą, wartością minimalną i maksymalną. Ponieważ T extends num, możesz bezpiecznie używać operatorów porównania i operacji arytmetycznych na wartościach — czego nie dałoby się zrobić w przypadku nieograniczonego typu generycznego.
Oczekiwany wynik:
Sum: 85
Min: 5
Max: 30
Sum: 11.6
Min: 1.2
Max: 4.8Spróbuj swoich sił
import 'stats.dart';
void main() {
// TODO: Utwórz Stats<int> z wartościami [10, 25, 5, 30, 15]
// i wywołaj printStats()
// TODO: Wypisz pustą linię
// TODO: Utwórz Stats<double> z wartościami [3.5, 1.2, 4.8, 2.1]
// i wywołaj printStats()
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy OOP
Pliki zewnętrzneBiblioteki i importyWprowadzenie do OOPKlasy a obiektySłowo kluczowe thisMetodyZmienne instancjiPodstawy konstruktorówPowtórka – prosty kalkulator4Bezpieczeństwo wartości null
Wprowadzenie do bezpieczeństwa wartości nullTypy dopuszczające null i niedopuszczające nullOperatory ? i !Słowo kluczowe late a bezpieczeństwo wartości nullOperatory uwzględniające nullBezpieczeństwo wartości null w klasachPodsumowanie — system profili użytkowników7Klasy abstrakcyjne i interfejsy
Klasy abstrakcyjneMetody abstrakcyjneInterfejsy w DartInterfejsy niejawneImplementowanie a rozszerzanieWiele interfejsówPowtórka — kalkulator kształtów10Kolekcje i typy generyczne
Przegląd List, Set i MapKolekcje bezpieczne typowoKlasy generyczneMetody generyczneOgraniczenia typów generycznychIterable i IteratorPowtórka — generyczne przechowywanie danych13Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieMetody rozszerzająceKlasy wywoływalneKlasy zapieczętowane (Dart 3)Rekordy (Dart 3)Wzorce i dopasowywanie (3.0)Typy wyliczeniowe z metodami16Projekt: Zarządzanie biblioteką
Omówienie projektuKlasy książek i użytkowników2Konstruktory w Dart
Konstruktor domyślnyKonstruktory nazwaneListy inicjalizująceKonstruktory stałeKonstruktory fabryczneKonstruktory przekierowującePodsumowanie — budowanie kształtów5Hermetyzacja
Elementy publiczne a prywatneKonwencja prefiksu _Prywatność na poziomie bibliotekiGettery i settery — szczegółowoUkrywanie informacjiPodsumowanie — dane uczniów8Domieszki
Wprowadzenie do domieszekTworzenie domieszekKorzystanie z wielu domieszekSłowo kluczowe on w domieszkachDomieszka a dziedziczenieDomieszka a interfejsPodsumowanie – system zwierząt11Metody specjalne
Nadpisanie toString()Nadpisanie hashCode i ==Interfejs ComparableMetoda call()Nadpisanie noSuchMethodPodsumowanie — własna kolekcja14Wzorce projektowe, część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec ObserverWzorzec Strategy3Właściwości klas
Elementy instancji a elementy statycznePola final i constZmienne inicjalizowane z opóźnieniemMetody i pola statyczneGettery i setteryPowtórzenie – menedżer kont bankowych6Dziedziczenie
Podstawy dziedziczeniaSłowo kluczowe superPrzesłanianie metodAdnotacja @overrideSłowo kluczowe final dla klasKonstruktory i dziedziczeniePowtórzenie – hierarchia pracowników9Polimorfizm
Podstawy polimorfizmuPolimorfizm za pomocą interfejsówSprawdzanie typu w czasie działaniaOperatory is i asSłowo kluczowe covariantPodsumowanie — procesor płatnościPoćwicz samodzielnie: Kompilator Dart online