2017-07-27 10 views
5

Otrzymuję błąd kompilacji Rust od sprawdzacza wypożyczeń i nie wiem, jak to naprawić.
Poniższy kod jest prosty i nie ma problemu z podobnym kodem w C++.Jak zaspokoić Checkera Rust z tym prostym kodem?

fn main() { 
    let mut nums = vec![1, 2, 3]; 
    if let Some(x) = nums.last() { 
     nums.push(*x); 
    } 
} 

Tutaj jest błąd:

message: 'cannot borrow `nums` as mutable because it is also borrowed as immutable (4, 9)' 
+1

nie wiedząc, rdza, to nie może jak robi Nums .last() w tej samej instrukcji co nums.push(), ponieważ wartość nums.last() może się zmienić po naciśnięciu nowego wpisu na nums. – jwenting

Odpowiedz

4

Można nieprawidłowego odniesienia w klauzuli Strażnik:

fn main() { 
    let mut nums = vec![1, 2, 3]; 
    if let Some(&x) = nums.last() { 
     nums.push(x); 
    } 
} 

Rust ma potężny wzór pasujący funkcji można rozpakować prawie wszystko, jeśli znasz jego typ. Sprawdź Rust pattern matching documentation.

+0

Dzięki, to działa. Myślałem, że nums.last() koliduje z nums.push(). Gdzie dokument Rust wyjaśnia szczegółowo "rozpakowanie odniesienia"? – LiLei

+0

@LiLei, zaktualizowałem odpowiedź, powinieneś rzucić okiem na wszystkie cechy pasujące do wzorca rdzy ma (słodki jak miód);) – Netwave

7

Po wywołaniu .last() pożyczysz nums jako niezmienną, ponieważ mutacja spowoduje unieważnienie posiadanego odniesienia x. Następnie należy wywołać .push, która pożycza nums jako zmienną.

Problemem jest to, że masz teraz niezmienna i jest zmienny pożyczyć tej samej wartości w tym samym czasie, co jest niezgodne z pamięcią rdzewieje gwarancje bezpieczeństwa (wielu czytelników lub jedna gwarancja pojedynczego pisarza, który nigdy nie będzie miało nieprawidłową pamięć gdziekolwiek).

fn main() { 
    let mut nums = vec![1, 2, 3]; 
    if let Some(x) = nums.last() { // Immutable borrow starts here 
     nums.push(*x);    // Mutable borrow starts here 
    }        // Immutable and mutable borrows end here 
} 

Rozwiązaniem byłoby obniżyć zakres niezmiennej pożyczyć od razu spada odniesienie jej wynik, jak na @ DanielSanchez na przykład:

let mut nums = vec![1, 2, 3]; 
if let Some(&x) = nums.last() { // Immutable borrow starts and ends here 
    nums.push(x);    // Mutable borrow starts here 
}        // Mutable borrow ends here 
+0

Dzięki, ta odpowiedź jest bardziej przejrzysta. Po prostu nie wiedziałem, dlaczego życie niezmiennego pożywienia się nie skończyło. Teraz wiem, powodem jest to, że zwracana wartość nums.last() jest odwołanie. Ale dlaczego "& x" może położyć kres trwałości? – LiLei

+2

w tym kontekście '& x' faktycznie dereferencje' x'. Normalnie przesuwałoby to 'x', ale liczby całkowite implementują cechę' Copy', co oznacza, że ​​zamiast przesuwać 'x' pracujemy z automatycznie wygenerowaną kopią' x'. Wywołanie przez nas 'x' niszczy referencję zwróconą przez' .last() 'i kończy pożyczkę, która spowodowała. –