2015-06-27 7 views
12

Najpierw Speak kodu:nie może pożyczyć `self.x` jako niezmienne, ponieważ` * self` jest także zapożyczone jako zmienny

#[derive(Debug)] 
struct Bar; 

#[derive(Debug)] 
struct Qux { 
    baz: bool 
} 

#[derive(Debug)] 
struct Foo { 
    bars: Vec<Bar>, 
    qux: Qux, 
} 

impl Foo { 
    fn get_qux(&mut self) -> &mut Qux { 
     &mut self.qux 
    } 

    fn run(&mut self) { 
     // 1. Fails: 
     let mut qux = self.get_qux(); 

     // 2. Works: 
     // let mut qux = &mut Qux { baz: false }; 

     // 3. Works: 
     // let mut qux = &mut self.qux; 

     let qux_mut = &mut qux; 
     qux_mut.baz = true; 

     for bar in &self.bars { 
      println!("{:?}", bar); 
     } 
    } 
} 

fn main() { 
    println!("Hello, world!"); 

    let mut foo = Foo { bars: vec!(), qux: Qux { baz: false } }; 
    foo.run(); 
} 

This błędów:

error[E0502]: cannot borrow `self.bars` as immutable because `*self` is also borrowed as mutable 
    --> src/main.rs:33:21 
    | 
22 |   let mut qux = self.get_qux(); 
    |      ---- mutable borrow occurs here 
... 
33 |   for bar in &self.bars { 
    |      ^^^^^^^^^ immutable borrow occurs here 
... 
36 |  } 
    |  - mutable borrow ends here 

Gdybym Odkomentuj albo 2. lub 3., dlaczego kompilacja jest w porządku? Wywoływana funkcja w 1. nie robi nic drastycznie innego niż 2. lub 3.. Dlaczego więc nie udało się skompilować 1.?

Chociaż istnieje many similar titled questions, nie mogłem jednoznacznie zidentyfikować tego jako duplikatu (innego niż komunikat o błędzie jest taki sam), prawdopodobnie z powodu mojego niezrozumienia systemu własności/pożyczek w firmie Rust.

Odpowiedz

8

W programie Rust kompilator zatrzymuje się na granicy wywołania funkcji podczas oceny ogólnych parametrów, które obejmują ogólne parametry cyklu życia. W twoim przypadku 1, dzwonisz metodę:

fn get_qux(&mut self) -> &mut Qux { 
    &mut self.qux 
} 

Funkcja ta wskazuje, że wszystko od self zostaną pożyczone mutably i że powrócił odniesienia będą żyć tak długo, jak self woli. W tym czasie nie można zaciągać innych pożyczek (zmiennych lub nie) ani ich składników.

W drugim przypadku tworzysz zupełnie nowy Qux, który nie ma żadnego powiązania z Twoją strukturą. To nie jest naprawdę świetny przykład, ponieważ ma zupełnie inne znaczenie. Jeśli ta sprawa sprawdza się w Twoim przypadku, powinieneś to zrobić:. Jednak nie będziesz modyfikować tego samego, co w przypadku 1.

W trzecim przypadku unikniesz wywołania funkcji. Oznacza to, że kompilator ma nieco więcej informacji o tym, co dokładnie jest pożyczane. W szczególności widać, że self.qux nie współdziała wcale z self.bars, więc nie występuje błąd.

Można dokonać oryginalnym przykładem pracy poprzez dodanie nowego zakresu:

fn run(&mut self) { 
    { 
     let mut qux = self.get_qux(); 
     let qux_mut = &mut qux; 
     qux_mut.baz = true; 
    } 

    for bar in &self.bars { 
     println!("{:?}", bar); 
    } 
} 

Tutaj sztuczny zakres jasno określa, gdzie kończy się zmienny pożyczyć. Po zakończeniu pożyczki inne przedmioty mogą zaciągać nowe pożyczki.

Jeśli trzeba zmodyfikować qux wewnątrz pętli, to są zobowiązane do przestrzegania trzeci wzór:

let mut qux = &mut self.qux; 

for bar in &self.bars { 
    qux.baz = ! qux.baz; 
    println!("{:?}", bar); 
} 

Albo prostsze:

for bar in &self.bars { 
    self.qux.baz = ! self.qux.baz; 
    println!("{:?}", bar); 
} 

wiele razy, możesz byłaby kodu tworzyć nowe struktury, które zawierają informacje i zawierają przyjemną granicę mutacji, aby stworzyć taki kod.

+3

Dziękuję za dokładną odpowiedź. Zastanawiam się jednak, jak można wtedy użyć 'qux' wewnątrz pętli for, jeśli musiałbym? –

+0

@FelixSchlitter zaktualizowany. – Shepmaster

+1

Rozumiem. Ale załóżmy, że funkcja ma w sobie dodatkową logikę, np. wziął identyfikator i wydobył "qux" z vec Quxes, wtedy musiałbym dodać tę logikę wszędzie. Może muszę uciekać się do makra? ...Wiem, że typy "HashMap" i "Vec" mają metodę "get_mut", być może jest też coś do nauczenia się z ich implementacji. Będę musiał wziąć kolejne nurkowanie. –

Powiązane problemy