Pisanie generycznego kodu w Rust
Nauczą się Państwo pisać funkcje i struktury danych działające z wieloma typami, zwiększając ponowne wykorzystanie kodu bez utraty bezpieczeństwa typów.
Pisanie generycznego kodu w Rust to bezpłatna lekcja Learn Rust Coding na CoddyKit. To lekcja 1 z 3. 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 3 lekcji w sumie.
Po co pisać kod generyczny?
Proszę wyobrazić sobie, że potrzebna jest funkcja znajdująca największy element na liście. Co zrobić, jeśli ma działać dla liczb, następnie dla znaków, a potem dla własnych obiektów?
Bez generyków trzeba byłoby napisać osobną funkcję dla każdego typu, co prowadziłoby do dużej ilości powielonego kodu. Właśnie tutaj przydają się generyki!
Wprowadzenie do generyków
Generyki umożliwiają pisanie kodu działającego z wieloma typami bez powtarzania kodu. Pozwalają tworzyć elastyczne funkcje i struktury danych wielokrotnego użytku.
Można myśleć o nich jak o projekcie, który można dostosować do różnych materiałów.
Pierwsza funkcja generyczna
Aby uczynić funkcję generyczną, należy zadeklarować parametry typów w nawiasach ostrych <> za nazwą funkcji. Często używaną nazwą parametru typu jest T (od Type).
Funkcja print_anything może teraz wypisywać wartości dowolnego typu!
fn print_anything<T>(item: T) {
println!("The item is: {}", item);
}
pub fn main() {
print_anything(5);
print_anything("hello");
print_anything(true);
}Wyjaśnienie parametrów typów
Zapis <T> w fn print_anything<T>(item: T) oznacza, że T jest symbolem zastępującym typ. Gdy funkcja zostanie wywołana z wartością typu i32, T staje się typem i32.
- Parametry typów: typy generyczne zwykle nazywa się wielkimi literami, takimi jak
T,UczyV. - Elastyczność: kompilator ustala konkretny typ podczas kompilacji.
Dodawanie zachowania: ograniczenia traitów
Czasami funkcja generyczna wymaga, aby jej parametr typu T miał określone zachowania. Jeśli na przykład chcą Państwo porównać dwa elementy typu T, typ T musi obsługiwać porównywanie.
Dodajemy ograniczenia traitów, aby określić te wymagania. W tym przypadku T: PartialOrd + Copy oznacza, że T musi implementować traity PartialOrd (częściowe uporządkowanie używane do porównań) oraz Copy.
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
let mut largest = list[0];
for &item in list.iter() {
if item > largest {
largest = item;
}
}
largest
}
pub fn main() {
let number_list = vec![34, 50, 25, 100, 65];
println!("Largest number: {}", largest(&number_list));
let char_list = vec!['y', 'm', 'a', 'q'];
println!("Largest char: {}", largest(&char_list));
}Składnia wielu ograniczeń traitów
Można wymagać od typu generycznego implementacji wielu traitów, używając składni +, na przykład T: TraitA + TraitB.
W przypadku złożonych ograniczeń można również użyć klauzuli where po sygnaturze funkcji, co może zwiększyć jej czytelność:
fn some_function<T, U>(t: T, u: U) -> i32 where T: Display + Clone, U: Clone + Debug { /* ... */ }
Struktury generyczne
Podobnie jak funkcje, struktury można definiować tak, aby przyjmowały jeden lub więcej parametrów typów. Dzięki temu struktury danych mogą przechowywać dane dowolnego określonego typu.
Struktura Point<T> może przechowywać współrzędne dowolnego typu T (na przykład i32 lub f64).
struct Point<T> {
x: T,
y: T,
}
pub fn main() {
let integer_point = Point {
x: 5,
y: 10
};
let float_point = Point {
x: 1.0,
y: 4.0
};
println!("Int Point: ({}, {})",
integer_point.x, integer_point.y);
println!("Float Point: ({}, {})",
float_point.x, float_point.y);
}Implementowanie metod dla struktur generycznych
Podczas implementowania metod dla struktury generycznej należy określić parametry typu po słowie kluczowym impl.
Do metod można również dodać ograniczenia traitów, jeśli dana metoda wymaga określonego zachowania od swoich typów generycznych.
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
pub fn main() {
let p = Point {
x: 5,
y: 10
};
println!("p.x = {}", p.x());
}Generyki a wydajność
Jedną z zalet Rust jest to, że generyki są abstrakcją bez kosztu. Oznacza to, że ich użycie nie powoduje spadku wydajności w czasie działania programu.
Rust osiąga to dzięki monomorfizacji: podczas kompilacji kompilator generuje wyspecjalizowane wersje kodu generycznego dla każdego konkretnego typu, z którym kod jest używany. Dlatego largest<i32> i largest<char> stają się dwiema odrębnymi, zoptymalizowanymi funkcjami.
Sprawdź swoją wiedzę
Które z poniższych stwierdzeń dotyczących generyków w Rust są PRAWDZIWE?
Podsumowanie: potęga generyków
W tej lekcji poznali Państwo podstawy pisania kodu generycznego w Rust:
- Czym są: sposobem na pisanie elastycznego kodu wielokrotnego użytku.
- Funkcje generyczne: wykorzystują
<T>jako parametr typu. - Ograniczenia traitów: określają wymagane zachowania za pomocą zapisu
T: Trait. - Struktury generyczne: umożliwiają tworzenie struktur danych przechowujących typy generyczne.
- Brak kosztu: generyki w Rust są kompilowane do konkretnego kodu, więc nie powodują spadku wydajności w czasie działania programu.
Generyki są podstawą idiomatycznego kodu Rust i umożliwiają tworzenie potężnych abstrakcji bezpiecznych typowo!
Często zadawane pytania
Czy lekcja „Pisanie generycznego kodu w Rust” jest bezpłatna?
Tak — pełny tekst „Pisanie generycznego kodu w Rust” 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 3 lekcji w sumie.
Co nauczysz się w „Pisanie generycznego kodu w Rust”?
Nauczą się Państwo pisać funkcje i struktury danych działające z wieloma typami, zwiększając ponowne wykorzystanie kodu bez utraty bezpieczeństwa typów. Ć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 3.
Ile czasu zajmuje lekcja „Pisanie generycznego kodu w Rust”?
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
- Pisanie generycznego kodu w Rust
- Definiowanie i implementowanie traitów
- Zaawansowane użycie traitów: typy powiązane