2015-07-04 9 views
6

Zaczynam się uczyć Rusta i próbowałem zaimplementować funkcję odwrócenia wektora ciągów znaków. Znalazłem rozwiązanie, ale nie rozumiem, dlaczego to działa.Dlaczego funkcja cloned() pozwala na kompilację tej funkcji?

to działa:

fn reverse_strings(strings:Vec<&str>) -> Vec<&str> { 
    let actual: Vec<_> = strings.iter().cloned().rev().collect(); 
    return actual; 
} 

Ale tego nie robi.

fn reverse_strings(strings:Vec<&str>) -> Vec<&str> { 
    let actual: Vec<_> = strings.iter().rev().collect(); // without clone 
    return actual; 
} 

Komunikat o błędzie

src/main.rs:28:10: 28:16 error: mismatched types: 
expected `collections::vec::Vec<&str>`, 
    found `collections::vec::Vec<&&str>` 
(expected str, 
    found &-ptr) [E0308] 

Czy ktoś może mi wyjaśnić dlaczego? Co dzieje się w drugiej funkcji? Dzięki!

Odpowiedz

10

Zatem wywołanie .cloned() jest zasadniczo podobne do wykonywania .map(|i| i.clone()) w tej samej pozycji (tj. Można zastąpić pierwszą z drugiej).

Chodzi o to, że po wywołaniu iter(), iteracji/pracy na odniesień do elementów będących iterowane. Zauważ, że wektor już składa się z "odnośników", w szczególności z wycinków łańcuchów.

Aby powiększyć nieco, zastąpmy cloned() odpowiednikiem map(), o którym wspomniałem powyżej, dla celów pedagogicznych, ponieważ są one równoważne. To jest to, co faktycznie wygląda:

.map(|i: & &str| i.clone()) 

więc zauważyć, że to odniesienie do odniesienia (wycinka), bo jak powiedziałem, iter() działa w odniesieniu do pozycji, a nie same pozycje. Ponieważ pojedynczy element w iterowanym iteracji jest typu &str, wówczas otrzymujemy do tego odniesienie, tj. & &str. Dzwoniąc pod numer clone() na każdym z tych elementów, przechodzimy od & &str do &str, tak jak wywołanie .clone() na &i64 może spowodować i64.

Aby wszystko zebrać razem, iter() iteruje po referencjach do elementów. Więc jeśli utworzyć nowy wektor z zebranych przedmiotów uzyskanych z iteracyjnej skonstruować (który skonstruowano poprzez wywołanie iter()) byś dostać wektor odniesień do odniesień, czyli:

let actual: Vec<& &str> = strings.iter().rev().collect(); 

więc przede wszyscy zdają sobie sprawę, że jest to , a nie taki sam, jak typ, który powtarza funkcja, Vec<&str>. Co ważniejsze jednak, okresy istnienia tych odniesień byłyby lokalne dla funkcji, więc nawet gdybyś zmienił typ zwrotu na Vec<& &str>, otrzymasz błąd długości życia.

Coś innego, co możesz zrobić, to użyć metody into_iter(). Ta metoda faktycznie powoduje, że iteruje nad każdym elementem, a nie odniesieniem do niego. Oznacza to jednak, że elementy są przeniesione z oryginalnego iteratora/kontenera. Jest to możliwe tylko w twojej sytuacji, ponieważ przekazujesz wektor według wartości, więc możesz przenosić elementy z niego.

fn reverse_strings(strings:Vec<&str>) -> Vec<&str> { 
    let actual: Vec<_> = strings.into_iter().rev().collect(); 
    return actual; 
} 

playpen

To prawdopodobnie czyni nieco więcej sensu niż klonowanie, ponieważ są przekazywane przez wartość wektora, my wolno robić niczego z elementów, w tym przeniesienie ich do innej lokalizacji (w tym przypadku nowy, odwrócony wektor). I, nawet jeśli nie, wektor zostanie upuszczony na końcu tej funkcji tak czy inaczej, więc równie dobrze moglibyśmy. Klonowanie byłoby bardziej odpowiednie, jeśli nie wolno nam tego robić (np. Jeśli przekazano nam wektor przez odniesienie, lub plasterek zamiast wektora byłby bardziej prawdopodobny).

Powiązane problemy