Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why do I get "cannot move out of … because it is borrowed" although no data is referenced?

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();
    drop(population);
    println!("{}", other.data);
}

Playground

The compiler claims that population cannot be dropped because it is borrowed in 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

I fail to see how both variables have a relationship with each other. I suspect the error to be in the select function as this is apparently the source of the borrow.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I have tried adding a separate lifetime to select (fn select<'b>(&self) -> Genotype<'b>) but that failed as I think that the compiler assumes that the lifetime of the Population instance is somehow linked with the returned Genotype even though it relates to the inner &str.

What am I doing wrong exactly?

>Solution :

I suspect the error to be in the select function as this is apparently the source of the borrow.

Yes.

the compiler assumes that the lifetime of the Population instance is somehow linked with the returned Genotype

Yes, that’s what your code says is the case.

even though it relates to the inner &str

What part of the select‘s function signature indicates that? Without specifically saying anything, you are relying on lifetime elision, so your function signature is the same as:

fn select<'x>(&'x self) -> Genotype<'x>

In words, that is: "I’m returning a Genotype that contains within it a reference that is guaranteed to be valid as long as &self is valid".

Instead, you likely want:

fn select(&self) -> Genotype<'a>

In words, that is: "I’m returning a Genotype that contains within it a reference that is guaranteed to be valid as long as the lifetime 'a is valid".


I strongly encourage everyone to add #![deny(rust_2018_idioms)] to the root of every crate. That will cause a compiler error for code like -> Genotype, prompting the programmer to think about exactly which lifetime is appropriate to place there.

Years of experience has shown that allowing lifetime elision to apply to structs with lifetimes inside of them was a bad choice and this lint helps improve the situation.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading