Historycznie jednym z zasad Rust było zapewnienie bezpieczeństwa typów i braku niejawnych konwersji, które prowadzą do błędów wykonania. Jednak dla wygody kodu częściowe automatyczne konwersje realizowane są przez deref coercion oraz traity From/Into, aby uprościć pracę z referencjami, inteligentnymi wskaźnikami, a także umożliwić uniwersalne API.
Problem pojawia się, gdy automatyczne konwersje mogą powodować zamieszanie, na przykład podczas przekazywania &String tam, gdzie oczekiwane jest &str. Wywoływana jest ukryta Deref::deref, a czasami pojawiają się nieprzewidziane konsekwencje (np. przy zmianie typu przekazywanych parametrów). Istnieje również kwestia bezpośredniego i jawnego castingu przez as.
Rozwiązanie: Rust wdraża surowe zasady deref-coercion dla wskaźników inteligentnych (Box, Rc, Arc) i ciągów (&String do &str, &Vec do &slice) na poziomie kompilatora. Dla jawnych konwersji przewidziane są traity From, Into, TryFrom, TryInto, as dla podstawowych castów. Unikanie błędów wspomaga statyczna typizacja i ograniczenie niejawnych konwersji.
Przykład kodu:
fn print_text(text: &str) { println!("{}", text); } let s = String::from("Hello!"); print_text(&s); // s: String, &s: &String, automatyczna konwersja do &str
Kluczowe cechy:
Czy deref coercion działa dla własnych typów, jeśli ręcznie zaimplementujesz Deref?
Tak, jeśli zaimplementujesz trait Deref dla swojego typu, kompilator będzie w stanie automatycznie konwertować, na przykład, twój wrapper do docelowego typu wewnątrz sygnatury funkcji, która oczekuje odpowiedniej referencji.
Czy deref coercion może zachodzić dla wartości, a nie dla referencji?
Nie, automatyczne dereferencjonowanie odbywa się tylko podczas przekazywania referencji, i tylko wtedy, gdy typ realizuje Deref.
Jakie są ograniczenia konwersji typów przez as podczas pracy z liczbami i enum?
as nie gwarantuje bezpieczeństwa: konwersja między typami liczb może spowodować przepełnienie lub utratę danych, a dla enum prowadzi do nie-semantycznych wartości (np. do niepoprawnej opcji enum).
Nowicjusz pisze funkcję, która przyjmuje &String i nie może używać &str bezpośrednio, wszędzie stosując text.to_string() z ciągu. To marnotrawstwo pamięci i wydajności.
Zalety:
Wady:
Funkcja przyjmuje argument typu &str, dzięki czemu może być wywoływana z dowolnym typem, który wspiera dereferencję lub konwersję: &str, &String, literały ciągowe. Nie są wymagane dodatkowe alokacje.
Zalety:
Wady: