"cannot exit a variable because it is borrowed" when rotating variables

I write a program that writes to a file and occasionally rotates the file that it writes. When I check to rotate the file, I cannot change the file because it is borrowed from my structure. Even if I drop instance of the structure, I cannot regain ownership of the file to rename it. Here is my example :

 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 } } 

I know that I can make this work by moving the file creation to a call to the new function of the FileStruct function instead of the intermediate variable file , but I would like to know why this method, where I force drop all variables, where all variable references should be returned, are not work.

+6
source share
2 answers

As the documentation std::mem::drop ,

While this calls for the implementation of the Drop argument, it will not release any roles since borrowing is based on the lexical domain.

That way, even if you call Drop , the file will still be borrowed.

+7
source

Discarding tmp does not โ€œrelease the loanโ€ file , because borrowing is lexically limited. It is "active" as long as program execution is within the lexical region containing tmp , even if you drop it. What you intended to do may be possible in the future if / once "non-lexical areas" are supported. Until then, you can make it work with 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 } 

The trick here is that given the general reference to RefCell<T> you can (eventually) get &mut T through borrow_mut() . The compilation borrow time counter is delighted because we only use a generic link on the surface, and it is normal to share a file with this. Variable anti-aliasing is eliminated by checking at runtime whether the internal T has already been used successfully.

+3
source

All Articles