Przejdź do głównej treści
eLearner.app
Moduł 5 · Lekcja 1 z 29/14 w kursie~12 min
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:

Code
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:

Code
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:

Code
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:

Code
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

Ćwiczenie#rust.m5.l1.e1
Próby: 0Ładowanie...

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.

Ładowanie edytora...
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

Ćwiczenie#rust.m5.l1.e2
Próby: 0Ładowanie...

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.

Ładowanie edytora...
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

Ćwiczenie#rust.m5.l1.e3
Próby: 0Ładowanie...

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>.

Ładowanie edytora...
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