I am writing a program that writes to a file and rotates the file it's writing to every now and then. When I check to rotate the file, I can't seem to change the file since it is borrowed by my struct. Even if I drop
the instance of the struct, I can't seem to 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 I can get this to work by moving the file creation into the new
function call of FileStruct
instead of having an intermediate variable, file
, but I would like to know why this method where I forcibly drop all the variables where all the variables references should be returned doesn't work.
As the
std::mem::drop
documentation says,So even if you call
drop
,file
will remain borrowed nonetheless.Dropping
tmp
does not "release the borrow" offile
because borrowing is lexically scoped. It's "active" as long as the program execution is within the lexical scope that containstmp
even if you drop it. What you intended to do might be possible in the future if/once "non-lexical scopes" are supported. Until then, you can make it work withRefCell
:The trick here is that given a shared reference to a
RefCell<T>
you can (eventually) get a&mut T
viaborrow_mut()
. The compile-time borrow checker is pleased because we only use a shared reference on the surface and it's OK to sharefile
like that. Mutable aliasing is avoided by checking at runtime whether the internalT
has already been mutably borrowed.