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.