rust - No se puede tomar prestado File from & mut self(mensaje de error: no se puede mover del contenido prestado)
borrow-checker (1)
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() {}
Compilar esto me dará:
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
¿Por qué está pasando esto? ¿Qué debo hacer para resolverlo?
self tiene el tipo &mut Foo print , es decir, es una referencia mutable prestada a un valor de tipo Foo . Los tipos en Rust mueven la propiedad por defecto, es decir, tomar algo por valor invalidará estáticamente la fuente y evitará que el programador la vuelva a usar (a menos que se reinicie). En este caso, unwrap tiene la firma:
impl Option<T> {
fn unwrap(self) -> T { ...
Es decir, toma el valor por valor de la Option y, por lo tanto, intenta consumir la propiedad del mismo. Por lo tanto, self.maybe_file.unwrap() está tratando de consumir los datos en maybe_file lo que dejaría self apuntado a datos parcialmente inválidos (es ilegal usar el campo maybe_file después de eso). No hay forma de que el compilador pueda hacer cumplir esto con referencias prestadas que deben ser válidas siempre, ya que podrían apuntar a cualquier parte, por lo que es ilegal mudarse.
Afortunadamente, uno puede evitar este problema: el método as_ref crea una Option<&T> partir de una &Option<T> y el método as_mut crea una Option<&mut T> de una &mut Option<T> . La Option resultante ya no está detrás de una referencia, por lo que es legal consumirla a través de unwrap :
let mut file = self.maybe_file.as_mut().unwrap();
Esto difiere ligeramente porque el file tiene el tipo &mut File lugar de File , pero afortunadamente &mut File es todo lo que necesita el resto del código.
Otro enfoque para hacer que esto funcione es usar la coincidencia manual de patrones:
match self.maybe_file {
Some(ref mut file) => println!(...),
None => panic!("error: file was missing")
}
Esto está haciendo exactamente lo mismo que el .as_mut().unwrap() solo más explícitamente: el ref mut es crear una referencia que apunta directamente a la memoria ocupada por self.maybe_file , al igual que as_mut .