2015-01-19 13 views
14
use std::fs::File; 
use std::io::Read; 

pub struct Foo { 
    maybe_file: Option<File>, 
} 

impl Foo { 
    pub fn init(&mut self) { 
     self.maybe_file = Some(File::open("/proc/uptime").unwrap()); 
    } 

    pub fn print(&mut self) { 
     let mut file = self.maybe_file.unwrap(); 
     let mut s = String::new(); 
     file.read_to_string(&mut s).unwrap(); 
     println!("Uptime: {}", s); 
    } 
} 

fn main() {} 

kompilowania To daje mi:Plik nie może pożyczyć od siebie i Mut (błąd msg: nie można wyprowadzić z pożyczonym zawartości)

error[E0507]: cannot move out of borrowed content 
    --> src/main.rs:14:24 
    | 
14 |   let mut file = self.maybe_file.unwrap(); 
    |      ^^^^ cannot move out of borrowed content 

Dlaczego tak się dzieje? Co mam zrobić, aby go rozwiązać?

Odpowiedz

30

self ma typ &mut Foo w print, to znaczy, że jest wypożyczony zmienny odniesienie do wartości typu Foo. Typy w Rust przenoszą własność domyślnie, to znaczy, biorąc coś za wartość, statycznie unieważnią źródło i powstrzymają programistę przed ponownym użyciem (chyba że zostanie ponownie zainicjowany). W tym przypadku, unwrap ma podpis:

impl Option<T> { 
    fn unwrap(self) -> T { ... 

to znaczy, że bierze wartość Option przez wartość, a więc starają się spożywać go na własność. W związku z tym self.maybe_file.unwrap() próbuje pobrać dane w postaci maybe_file, co pozostawiłoby self wskazujące na częściowo nieprawidłowe dane (niedozwolone jest używanie pola maybe_file). Kompilator nie może tego egzekwować za pomocą pożyczonych odniesień, które muszą być zawsze aktualne, ponieważ mogą wskazywać gdziekolwiek, więc wyprowadzanie się jest nielegalne.

Na szczęście, można uniknąć tego problemu: metoda as_ref tworzy Option<&T> się o &Option<T> i metoda as_mut tworzy Option<&mut T> się o &mut Option<T>. Powstały Option nie jest już wtedy za punkt odniesienia, a więc jest to legalne spożywanie go przez unwrap:

let mut file = self.maybe_file.as_mut().unwrap(); 

ta różni się nieznacznie, ponieważ file ma typ &mut File zamiast File, ale na szczęście &mut File jest wszystko, co jest niezbędne dla reszta kodu.

Innym podejściem do podejmowania tej pracy jest za pomocą ręcznego dopasowywania wzoru:

match self.maybe_file { 
    Some(ref mut file) => println!(...), 
    None => panic!("error: file was missing") 
} 

To robi dokładnie to samo co .as_mut().unwrap() tylko bardziej wyraźny: the ref mut jest utworzyć odwołanie skierowaną bezpośrednio do pamięci zajmowanej przez self.maybe_file, podobnie jak as_mut.

+1

Dzięki, ta odpowiedź bardzo mi pomogła! – Reignbeaux

Powiązane problemy