Menu
Coddy logo textTech

Funkcje generyczne

Część sekcji Programowanie obiektowe ścieżki Rust w Coddy. Lekcja 27 z 61.

Generyki nie ograniczają się do struktur. Możesz również pisać samodzielne funkcje, które działają z dowolnym typem. Jest to przydatne, gdy potrzebujesz funkcji pomocniczej, która nie należy do konkretnej struktury, ale powinna być elastyczna.

Składnia przypomina tę, którą znasz już ze struktur. Zadeklaruj parametr generyczny w nawiasach ostrych po nazwie funkcji, a następnie użyj go w parametrach i typie zwracanym:

fn identity<T>(value: T) -> T {
    value
}

Ta funkcja identity przyjmuje wartość dowolnego typu i zwraca ją bez zmian. <T> deklaruje parametr generyczny, value: T przyjmuje go jako parametr, a -> T określa typ zwracany. Gdy wywołujesz funkcję, Rust wnioskuje konkretny typ:

let num = identity(42);        // T jest i32
let text = identity("hello");  // T jest &str

Możesz także używać wielu parametrów generycznych w funkcjach, tak jak w strukturach:

fn make_pair<T, U>(first: T, second: U) -> (T, U) {
    (first, second)
}

let pair = make_pair(10, "ten");  // zwraca (i32, &str)

Funkcje generyczne pozwalają napisać logikę wielokrotnego użytku raz i stosować ją do wielu typów, ograniczając powielanie kodu przy zachowaniu bezpieczeństwa typów.

challenge icon

Wyzwanie

Łatwy

Zbudujmy moduł narzędziowy z funkcjami generycznymi, które mogą działać z dowolnym typem! Utworzysz samodzielne funkcje pokazujące, jak generyczność sprawia, że Twój kod jest elastyczny i wielokrotnego użytku, bez powiązania z konkretną strukturą.

Rozmieścisz kod w dwóch plikach:

  • utils.rs: Utwórz zestaw publicznych generycznych funkcji narzędziowych:
    • wrap_in_pair<T>: przyjmuje pojedynczą wartość i zwraca krotkę zawierającą tę wartość dwukrotnie: (value, value). Wymaga to, aby typ implementował cechę Clone, więc użyj <T: Clone>
    • swap<T, U>: przyjmuje dwie wartości, które mogą mieć różne typy, i zwraca je w odwrotnej kolejności jako krotkę (U, T)
  • main.rs: Zaimportuj moduł narzędziowy i pokaż działanie tych funkcji generycznych na różnych typach. Pokaż, jak te same definicje funkcji bezproblemowo obsługują liczby całkowite, liczby zmiennoprzecinkowe i ciągi znaków.

W pliku głównym pokaż działanie funkcji narzędziowych, wykonując następujące czynności:

  1. Użyj wrap_in_pair z liczbą całkowitą (pierwsze wejście, sparsowane jako i32) i wypisz oba elementy
  2. Użyj wrap_in_pair z ciągiem znaków (drugie wejście) i wypisz oba elementy
  3. Użyj swap z liczbą całkowitą (trzecie wejście, sparsowane jako i32) i ciągiem znaków (czwarte wejście), a następnie wypisz wynik zamiany kolejności

Wynik powinien mieć następujący format:

Pair of ints: ({value}, {value})
Pair of strings: ({value}, {value})
Swapped: ({string}, {int})

Na przykład dla wejść 5, hello, 42 i world:

Pair of ints: (5, 5)
Pair of strings: (hello, hello)
Swapped: (world, 42)

Zwróć uwagę, że wrap_in_pair działa identycznie zarówno dla liczb całkowitych, jak i ciągów znaków, a swap obsługuje dwa zupełnie różne typy: na tym polega elastyczność funkcji generycznych!

Otrzymasz cztery wejścia: liczbę całkowitą, ciąg znaków, kolejną liczbę całkowitą i kolejny ciąg znaków.

Spróbuj swoich sił

mod utils;

use std::io;

fn main() {
    // Wczytaj cztery dane wejściowe
    let mut input1 = String::new();
    io::stdin().read_line(&mut input1).expect("Failed to read line");
    let num1: i32 = input1.trim().parse().expect("Invalid integer");

    let mut input2 = String::new();
    io::stdin().read_line(&mut input2).expect("Failed to read line");
    let str1 = input2.trim().to_string();

    let mut input3 = String::new();
    io::stdin().read_line(&mut input3).expect("Failed to read line");
    let num2: i32 = input3.trim().parse().expect("Invalid integer");

    let mut input4 = String::new();
    io::stdin().read_line(&mut input4).expect("Failed to read line");
    let str2 = input4.trim().to_string();

    // TODO: Użyj wrap_in_pair z num1 i wypisz wynik
    // Format: Pair of ints: ({value}, {value})

    // TODO: Użyj wrap_in_pair z str1 i wypisz wynik
    // Format: Pair of strings: ({value}, {value})

    // TODO: Użyj swap z num2 i str2, a następnie wypisz wynik zamiany
    // Format: Swapped: ({string}, {int})
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Rust online