rust borrow-checker

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 .