2015-11-30 8 views
5

Piszę program, który zapisuje do pliku i obraca plik, który pisze do każdego od czasu do czasu. Kiedy sprawdzam, aby obrócić plik, nie mogę zmienić pliku, ponieważ jest zapożyczony przez moją strukturę. Nawet jeśli I drop wystąpienie struktury, nie wydaje się, aby odzyskać własność pliku, aby zmienić nazwę. Oto mój example:"nie można przenieść ze zmiennej, ponieważ jest wypożyczona" podczas obracania zmiennych

use std::fs::File; 
use std::io::{Write}; 
use std::mem::{drop}; 

pub struct FileStruct<W: Write> { 
    pub writer: Option<W>, 
} 

impl <W: Write> FileStruct<W> { 
    pub fn new(writer: W) -> FileStruct<W> { 
     FileStruct { 
      writer: Some(writer), 
     } 
    } 
} 

fn main() { 
    let mut file = File::create("tmp.txt").unwrap(); 
    let mut tmp = FileStruct::new(&mut file); 
    loop { 
     if true { //will be time based if check 
      drop(tmp); 
      drop(file); 
      file = File::create("tmp2.txt").unwrap(); 
      tmp = FileStruct::new(&mut file); 
     } 
     // write to file 
    } 
} 

wiem, że mogę dostać tę pracę przesuwając tworzenia plików do wywołania new funkcyjnym FileStruct zamiast zmiennej pośredniej, file, ale chciałbym wiedzieć, dlaczego metoda, w której siłą odrzucam wszystkie zmienne, w których wszystkie zmienne, które mają zostać zwrócone, nie działa.

+0

Potrzebujesz 'tmp' poza blokiem if? Jeśli nie, możesz upewnić się, że pożycza się przed ponownym przypisaniem "pliku". – fjh

+0

Ja to robię. Chodzi o to, że piszę dane w pętli, a blok if zmienia plik wyjściowy. Blok if jest przeznaczony dla mnie do określenia, czy powinienem zmienić 'plik'. –

Odpowiedz

6

Jak the std::mem::drop documentation mówi

Chociaż nie nazywają realizację argument dotyczącą Drop, nie wyda żadnych pożycza, jak pożycza są na podstawie zakresu leksykalnego.

Więc nawet jeśli zadzwonisz drop, file pozostanie mimo wszystko pożyczone.

+0

Oto kilka informacji na temat możliwych zakresów innych niż leksykalne: https://github.com/rust-lang/rfcs/issues/811 –

2

Upuszczenie tmp nie "zwalnia pożyczki" z file, ponieważ pożyczanie ma zasięg leksykalny. Jest "aktywny", dopóki wykonanie programu mieści się w zakresie leksykalnym, który zawiera tmp, nawet jeśli go upuścisz. To, co zamierzałeś zrobić, może być możliwe w przyszłości, jeśli/raz obsługiwane będą "nielekowe zakresy". Do tego czasu, można zrobić to praca z RefCell:

use std::cell::RefCell; 
use std::io::{ self, Write }; 

/// wraps a reference to a RefCell<W> 
struct RefCellWriteRef<'a, W: 'a>(&'a RefCell<W>); 

/// implement Write for when W is Write 
impl<'a, W: Write + 'a> Write for RefCellWriteRef<'a, W> { 
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 
     let mut w = self.0.borrow_mut(); 
     w.write(buf) 
    } 
    fn flush(&mut self) -> io::Result<()> { 
     let mut w = self.0.borrow_mut(); 
     w.flush() 
    } 
} 

fn main() { 
    let file: RefCell<Vec<u8>> = RefCell::new(Vec::new()); 
    // use RefCellWriteRef(&file) instead of &mut file 
    let mut tmp = RefCellWriteRef(&file); 
    for iter in 0..10 { 
     if iter == 5 { 
      drop(tmp); 
      file.borrow_mut().clear(); // like opening a new file 
      tmp = RefCellWriteRef(&file); 
     } 
     tmp.write(b"foo").unwrap(); 
    } 
    drop(tmp); 
    println!("{}", file.borrow().len()); // should print 15 
} 

Sztuką jest to, że biorąc pod uwagę wspólne odniesienie do RefCell<T> można (ewentualnie) dostać &mut T poprzez borrow_mut(). Sprawdzanie pożyczek podczas kompilacji jest satysfakcjonujące, ponieważ używamy tylko współużytkowanych referencji na powierzchni i można w ten sposób udostępniać file. Modyfikowanie aliasingu jest unikane poprzez sprawdzenie w czasie pracy, czy wewnętrzna kamera T została już zapożyczona w sposób łagodny.

Powiązane problemy