for*_*ave 18 rust borrow-checker
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() {}
Run Code Online (Sandbox Code Playgroud)
编译这将给我:
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
Run Code Online (Sandbox Code Playgroud)
为什么会这样?我该怎么做才能解决它?
huo*_*uon 35
self已键入&mut Foo在print,即,它是一个借用的可变引用类型的值Foo.Rust中的类型默认情况下移动所有权,也就是说,取值by-value将静态地使源无效并阻止程序员再次使用它(除非它被重新初始化).在这种情况下,unwrap有签名:
impl Option<T> {
fn unwrap(self) -> T { ...
Run Code Online (Sandbox Code Playgroud)
也就是说,它取Option价值按值,从而试图消耗它的所有权.因此,self.maybe_file.unwrap()试图消耗maybe_file其中会留下self部分无效数据的数据(maybe_file之后使用该字段是非法的).编译器无法使用借用的引用强制执行此操作,这些引用必须始终有效,因为它们可以指向任何位置,因此移出是非法的.
幸运的是,人们可以避免这个问题:该as_ref方法创建了一个Option<&T>out,&Option<T>并且该as_mut方法创建了一个Option<&mut T>out &mut Option<T>.结果Option不再是引用的后面,因此通过unwrap以下方式使用它是合法的:
let mut file = self.maybe_file.as_mut().unwrap();
Run Code Online (Sandbox Code Playgroud)
这略有不同,因为file有类型&mut File而不是File,但幸运的&mut File是其余代码所需的全部内容.
另一种方法是使用手动模式匹配:
match self.maybe_file {
Some(ref mut file) => println!(...),
None => panic!("error: file was missing")
}
Run Code Online (Sandbox Code Playgroud)
这与.as_mut().unwrap()更明确的做法完全相同:ref mut创建一个直接指向占用内存的引用self.maybe_file,就像as_mut.