es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Por qué recibo el mensaje “no se puede mover fuera de … porque está prestado” aunque no se hace referencia a ningún dato?

struct Population<'a> {
    dat: Vec<genotype<'a>>,
}

impl<'a> Population<'a> {
    fn new(dat: Vec<genotype<'a>>) -> Self {
        Population { dat }
    }

    fn select(&self) -> Genotype<'a> {
        self.dat.first().unwrap().clone()
    }
}

#[derive(Clone)]
struct Genotype<'a> {
    data: &'a str,
}

impl<'a> Genotype<'a> {
    fn new(data: &'a str) -> Self {
        Genotype { data }
    }
}

fn main() {
    let hello = "Hello World";
    let genotype = Genotype::new(hello);
    let mut population = Population::new(vec![genotype]);

    let other = population.select();
    drop(population);
    println!("{}", other.data);
}

El compilador indica que no se puede descartar population porque está siendo prestado en other:

error[E0505]: cannot move out of `population` because it is borrowed
  --> src/main.rs:32:10
   |
31 |     let other = population.select();
   |                 ------------------- borrow of `population` occurs here
32 |     drop(population);
   |          ^^^^^^^^^^ move out of `population` occurs here
33 |     println!("{}", other.data);
   |                    ---------- borrow later used here

No entiendo cómo ambas variables están relacionadas entre sí. Sospecho que el error está en la función select ya que aparentemente es la fuente del préstamo.

He intentado agregar un lifetime separado a select (fn select<'b>(&self) -> Genotype<'b>) pero falla, ya que parece que el compilador asume que el lifetime de la instancia de Population está de alguna manera vinculado con el Genotype devuelto, aunque se refiere al &str interno.

¿Qué estoy haciendo mal exactamente?</genotype<‘a></genotype<‘a>

Tags:  ,

Answer

  1. Avatar for davy.ai

    El problema con el código es que el método select devuelve un Genotype que contiene una referencia a los datos propiedad de la instancia Population. Cuando llamas a select() en population, estás tomando prestada population para obtener la referencia a los datos. Esto significa que population no puede ser eliminada hasta que other salga de alcance, ya que other aún tiene una referencia a los datos propiedad de population.

    Para solucionar el problema, puedes cambiar select para que devuelva una copia de los datos de Genotype en lugar de una referencia. De esta manera, la instancia de Genotype devuelta por select será propietaria de sus datos y no habrá una relación de préstamo entre ella y population. Así es como puedes modificar el código para hacerlo:

    struct Population<'a> {
        dat: Vec<genotype<'a>>,
    }
    
    impl<'a> Population<'a> {
        fn new(dat: Vec<genotype<'a>>) -> Self {
            Population { dat }
        }
    
        fn select(&self) -> Genotype {
            self.dat.first().unwrap().clone()
        }
    }
    
    #[derive(Clone)]
    struct Genotype<'a> {
        data: &'a str,
    }
    
    impl<'a> Genotype<'a> {
        fn new(data: &'a str) -> Self {
            Genotype { data }
        }
    }
    
    fn main() {
        let hello = "Hello World";
        let genotype = Genotype::new(hello);
        let mut population = Population::new(vec![genotype]);
    
        let other = population.select().clone(); // clonar los datos de la instancia de Genotype
        drop(population);
        println!("{}", other.data);
    }
    

    Observa que modificamos el método select para que devuelva Genotype en lugar de Genotype<'a>, porque el valor devuelto será propietario de sus datos en lugar de tomarlos prestados. Además, cuando llamamos a select en main, necesitamos llamar a clone en la instancia de Genotype devuelta para hacer una copia de sus datos. Esto nos permite eliminar population sin ningún problema.

    Con estos cambios, el código ahora se compila sin errores.</genotype<‘a></genotype<‘a>

Comments are closed.