我正在编写一个程序,该程序写入文件并随时旋转它所写的文件。当我检查旋转文件时,我似乎无法更改文件,因为它是由我的struct借用的。即使我drop
结构的实例,我似乎无法重新获得文件的所有权来重命名它。
这是我的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
}
}
我知道可以得到这个通过移动文件创建到的new
,而不是具有一个中间变量,FileStruct
,但我想知道file
的函数调用工作为什么我强行删除应该返回所有变量引用的所有变量的方法不起作用。
答案 0 :(得分:7)
正如the std::mem::drop
documentation所说,
虽然这确实调用了
Drop
的参数的实现,但它不会释放任何借用,因为借用是基于词法范围的。
因此,即使您致电drop
,file
仍将继续借用。
答案 1 :(得分:3)
删除tmp
不会“释放file
的借用”,因为借用是词法范围的。只要程序执行在包含tmp
的词法范围内,即使你删除它,它也是“活动的”。如果/一旦支持“非词法范围”,您将来可能会做什么。在此之前,您可以使用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
}
这里的诀窍是,如果给RefCell<T>
共享引用,您可以(最终)通过&mut T
获得borrow_mut()
。编译时借用检查器很高兴,因为我们只在表面上使用共享引用,可以像这样共享file
。通过在运行时检查内部T
是否已被可变地借用来避免可变别名。