Lekcje modułu (1/2)
Typy generyczne i funkcje
Typy generyczne (Generics) pozwalają na pisanie elastycznego kodu wielokrotnego użytku, unikając duplikowania logiki dla różnych typów danych. Zamiast definiować wiele funkcji lub struktur dla różnych typów (jak i32, f64 czy String), możemy użyć parametru typu generycznego, konwencjonalnie oznaczanego literą T.
Kompilator Rusta zarządza typami generycznymi poprzez proces zwany monomorfizacją (monomorfizzazione): podczas kompilacji kompilator generuje kopię kodu generycznego dla każdego konkretnego typu, z którym jest on rzeczywiście używany. W ten sposób nie ma żadnego narzutu wydajnościowego w czasie wykonywania programu.
Funkcje generyczne
Aby zdefiniować funkcję generyczną, umieszczamy parametr typu <T> tuż po nazwie funkcji, a przed listą parametrów:
fn print_value<T: std::fmt::Debug>(value: T) {
println!("Valore: {:?}", value);
}
W funkcjach generycznych możemy użyć typu generycznego T zarówno dla typów argumentów, jak i dla typu zwracanego:
fn identity<T>(value: T) -> T {
value
}
Struktury generyczne
Parametry typu generycznego możemy stosować również wewnątrz struktur danych (struct) do definiowania elastycznych pól:
struct KeyValuePair<K, V> {
key: K,
value: V,
}
fn main() {
let pair = KeyValuePair {
key: String::from("eta"),
value: 30,
};
}
W bloku impl dla generycznej struktury musimy zadeklarować parametr typu <T> bezpośrednio po słowie kluczowym impl, aby wskazać, że implementujemy metody na strukturze generycznej:
struct Container<T> {
value: T,
}
impl<T> Container<T> {
fn new(value: T) -> Self {
Container { value }
}
fn value(&self) -> &T {
&self.value
}
}
Spróbuj sam
Esercizio 1: Struktura Point
Zdefiniuj generyczną strukturę o nazwie Point<T> z dwoma polami: x typu T oraz y typu T. W funkcji main utwórz instancję zmiennej point zawierającą Point o wartościach x równym 5 i y równym 10 (liczby całkowite), a następnie wypisz na ekranie wartość point.x.
Pokaż wskazówkę
Zadeklaruj strukturę za pomocą `struct Point<T> { x: T, y: T }`. Utwórz jej instancję w main i użyj `point.x` do jej wypisania.
Rozwiązanie dostępne po 3 próbach
Esercizio 2: Odwracanie krotki za pomocą swap
Napisz generyczną funkcję o nazwie swap<T>, która przyjmuje jako argument krotkę dwóch elementów (T, T) i zwraca nową krotkę (T, T) z elementami o odwróconych pozycjach. W funkcji main wywołaj funkcję z krotką (1, 2) i wypisz wynik.
Pokaż wskazówkę
Sygnatura funkcji powinna wyglądać następująco: `fn swap<T>(pair: (T, T)) -> (T, T)`. Zwróć odwróconą krotkę za pomocą `(pair.1, pair.0)`.
Rozwiązanie dostępne po 3 próbach
Esercizio 3: Struktura Container
Zdefiniuj generyczną strukturę Container<T> zawierającą pole value typu T. Zaimplementuj generyczny blok impl do zdefiniowania metody new, która przyjmuje wartość typu T i zwraca instancję Container<T>.
Pokaż wskazówkę
Użyj `impl<T> Container<T>`do zaimplementowania metody powiązanej`fn new(value: T) -> Self { Container { value } }`.
Rozwiązanie dostępne po 3 próbach