programowanieProgramista Rust

Jak w Rust działa praca z kolekcjami (np. Vec, HashMap)? Jakie są szczególne cechy ich własności i kiedy należy klonować elementy lub kolekcję?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

W standardowych kolekcjach Rust (takich jak Vec<T>, HashMap<K,V>, HashSet<T> itd.) realizowana jest zasada własności zawartości. Oznacza to, że kolekcja posiada wszystkie obiekty, które zawiera, i jest odpowiedzialna za zwolnienie ich pamięci przy usunięciu.

Na przykład, elementy umieszczone w Vec<T> są przenoszone (move) do wektora, który następnie nimi włada:

let s = String::from("hi"); let mut v = Vec::new(); v.push(s); // s jest teraz przeniesione, nie jest dostępne

Jeśli kolekcja zawiera wartości kopii, są one kopiowane; jeśli przenośne, prawa własności są przekazywane. Klonowanie elementów lub kolekcji jest konieczne, gdy trzeba zachować oryginalną wartość w dwóch miejscach, na przykład:

let name = String::from("Olga"); let mut v = Vec::new(); v.push(name.clone()); println!("{}", name); // name wciąż jest dostępne, ponieważ zostało sklonowane

Pytanie z haczykiem

Co się dzieje podczas wstawiania elementu do HashMap, jeśli używa się przenośnego typu danych (np. String) jako klucza? Czy oryginalny klucz będzie dostępny po jego przekazaniu do HashMap::insert()?

Często podawana jest błędna odpowiedź: "Oryginalny klucz pozostanie dostępny po wstawieniu".

W rzeczywistości własność klucza i wartości jest przekazywana do HashMap, a po wstawieniu nie można ich używać bez wcześniejszego sklonowania:

let key = String::from("id"); let mut map = std::collections::HashMap::new(); map.insert(key, 42); // klucz nie jest już dostępny

Próba odwołania się do key spowoduje błąd kompilacji.

Przykłady rzeczywistych błędów z powodu niewiedzy na temat niuansów tematu


Historia Programista próbował użyć przeniesionego obiektu po wstawieniu do Vec i otrzymał błąd "value used here after move", nie rozumiejąc, że teraz Vector nim włada.


Historia Pracując z HashMap, zapomniano sklonować klucze tekstowe, co doprowadziło do niemożności ich użycia w innych miejscach, co wymagało znacznego refaktoryzowania kodu.


Historia W jednym z projektów próbowano zwrócić odwołanie do wewnętrznego elementu wektora poza funkcję, zapominając, że odwołanie zostanie unieważnione po zmianie rozmiaru wektora. To doprowadziło do powstania dangling references i awarii w czasie wykonania (panic).