0Pricing
Learn Rust Coding · Lekcja

Funkcje generyczne

Sparametryzuje Pan/Pani zachowanie typem.

Funkcje generyczne to bezpłatna lekcja Learn Rust Coding na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Learn Rust Coding, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Learn Rust Coding zawiera 4 lekcji w sumie.

Po co używać funkcji generycznych

Funkcje generyczne pozwalają napisać jedną funkcję działającą z wieloma typami zamiast kopiować kod dla każdego typu. Rust zastępuje typ zastępczy właściwym typem podczas kompilacji.

Wyobraź sobie napisanie jednej funkcji largest dla liczb całkowitych i drugiej dla znaków. Typy generyczne łączą je w jedną definicję bez kosztu działania w czasie wykonywania.

Parametry typów

Funkcja generyczna deklaruje parametr typu w nawiasach ostrych umieszczonych po nazwie. Nazwa T jest konwencją, ale można użyć dowolnego identyfikatora w stylu CamelCase.

Parametr może następnie pojawić się w argumentach i typie zwracanym, zastępując konkretny typ używany przez wywołującego.

fn first<T>(pair: (T, T)) -> T {
    pair.0
}

Prosta funkcja tożsamościowa

Ten program definiuje generyczną funkcję echo, która zwraca swój argument bez zmian. Jest wywoływana raz z liczbą całkowitą, a raz z wycinkiem łańcucha znaków.

Kompilator generuje osobną konkretną wersję dla każdego rzeczywiście użytego typu.

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

fn main() {
    println!("{}", echo(42));
    println!("{}", echo("hi"));
}

Monomorfizacja

Rust stosuje monomorfizację: podczas kompilacji tworzy wyspecjalizowaną kopię funkcji dla każdego użytego konkretnego typu. Nie występuje tu opakowywanie ani dynamiczne wywołanie metod.

W rezultacie kod generyczny działa równie szybko jak ręcznie napisany kod zależny od konkretnego typu.

Typy generyczne potrzebują ograniczeń

W funkcji generycznej można używać tylko operacji obsługiwanych przez każdy możliwy typ. Samo T nie może być dodawane, porównywane ani wyświetlane.

Ten kod nie kompiluje się, ponieważ T może nie implementować porównywania. W następnej części naprawimy to za pomocą ograniczenia cechy.

fn larger<T>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

Dodawanie ograniczenia cechy

Aby porównywać wartości, ograniczamy T za pomocą PartialOrd. To ograniczenie gwarantuje, że typ obsługuje operator >.

Dodajemy także Copy, aby można było zwracać wartości bez problemów z przenoszeniem w przypadku prostych typów, takich jak liczby całkowite.

fn larger<T: PartialOrd + Copy>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

Wywoływanie funkcji z ograniczeniami

Teraz funkcja działa dla każdego typu implementującego obie cechy. Liczby całkowite i zmiennoprzecinkowe spełniają ograniczenie PartialOrd + Copy.

Ten sam kod źródłowy, zmonomorfizowany do dwóch wersji, wyświetla wyniki dla każdego wywołania.

fn larger<T: PartialOrd + Copy>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

fn main() {
    println!("{}", larger(3, 9));
    println!("{}", larger(2.5, 1.0));
}

Wiele parametrów typów

Funkcja może deklarować kilka parametrów typów. Każdy z nich jest niezależny, dlatego oba argumenty mogą mieć różne typy.

W tym przypadku pair przyjmuje dowolne T i dowolne U, a następnie zwraca je jako krotkę.

fn pair<T, U>(a: T, b: U) -> (T, U) {
    (a, b)
}

Wyświetlanie wartości generycznych

Aby wyświetlić wartość generyczną za pomocą {}, typ musi implementować Display. Dodajemy to ograniczenie, aby można było przekazywać dowolny typ obsługujący wyświetlanie.

Funkcja oznacza wartość i ją zwraca, pokazując ograniczenie używane wyłącznie do formatowania.

use std::fmt::Display;

fn announce<T: Display>(label: &str, value: T) {
    println!("{}: {}", label, value);
}

fn main() {
    announce("count", 7);
    announce("name", "Ada");
}

Składnia turbofish

Czasami kompilator nie może wywnioskować T na podstawie samych argumentów. Turbofish ::<Type> pozwala jawnie określić typ w miejscu wywołania.

Najczęściej używa się go z metodami takimi jak parse i collect, gdy typ zwracany jest niejednoznaczny.

fn main() {
    let n = "42".parse::<i32>().unwrap();
    println!("{}", n + 1);
}

Typy generyczne dla referencji

Parametry generyczne działają także z referencjami. Ograniczenie oparte na referencji pozwala uniknąć wymagania Copy, gdy potrzebny jest tylko odczyt wartości.

Ten pomocniczy kod w stylu longest_str pożycza dwa wycinki i zwraca jeden z nich bez przejmowania własności.

fn pick<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> &'a T {
    if a > b { a } else { b }
}

Szybkie sprawdzenie

Sprawdź swoją wiedzę na temat funkcji generycznych w Rust.

Podsumowanie

Funkcje generyczne używają parametrów typów w nawiasach ostrych, aby działać z wieloma typami bez kosztu w czasie wykonywania dzięki monomorfizacji.

Operacje na typie generycznym wymagają ograniczeń cech, takich jak PartialOrd, Copy lub Display. Użyj turbofish, gdy kompilator nie może wywnioskować typu.

Często zadawane pytania

Czy lekcja „Funkcje generyczne” jest bezpłatna?

Tak — pełny tekst „Funkcje generyczne” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Learn Rust Coding, przejdź na CoddyKit PRO. Kurs Learn Rust Coding zawiera 4 lekcji w sumie.

Co nauczysz się w „Funkcje generyczne”?

Sparametryzuje Pan/Pani zachowanie typem. Ćwiczysz Learn Rust Coding z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Learn Rust Coding?

Nie wymagamy żadnego doświadczenia. Learn Rust Coding w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.

Ile czasu zajmuje lekcja „Funkcje generyczne”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Learn Rust Coding?

Tak. Każda lekcja Learn Rust Coding zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Funkcje generyczne
  2. Generyczne struktury i enumy
  3. Ograniczenia traitów
  4. Klauzule where i wiele ograniczeń
← Powrót do Learn Rust Coding