0

I need to iterate a vector with structs in each iteration in a loop. It works fine as long as the vector doesn't contain structs. I have tried many different solutions but always get some kind of ownership problem.

What am I doing wrong?

struct Element {
    title: String,
}

impl Element {
    pub fn get_title(self) -> String {
        self.title
    }
}

fn main() {
    let mut items: Vec<Element> = Vec::new();
    items.push(Element {
        title: "Random".to_string(),
    });
    items.push(Element {
        title: "Gregor".to_string(),
    });

    let mut i = 0;
    while i < 10 {
        for item in &items {
            println!("Loop {} item {}", i, item.get_title());
        }
        i = i + 1;
    }
}

playground

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:23:44
   |
23 |             println!("Loop {} item {}", i, item.get_title());
   |                                            ^^^^ cannot move out of borrowed content
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
cjohansson
  • 1,058
  • 10
  • 13
  • I advice you to read the [book](https://doc.rust-lang.org/stable/book/) – Stargateur Apr 02 '19 at 07:15
  • Thanks I have read the book 3 times, I can't understand how you can think this is duplicate question. The other question accesses same variable in two dimensional loop, my question doesn't – cjohansson Apr 02 '19 at 07:24
  • 2
    "The other question accesses same variable in two dimensional loop, my question doesn't" that doesn't change anything. The point of the duplication is that if you iter so you borrow the value you can't use function that consume the value. – Stargateur Apr 02 '19 at 07:51
  • Note that you can drastically [simplify your example by manually unrolling the loop](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=cd22d9c91a0a5a46c33c089800822b3e). Once you've made it as simple as possible, it's more apparent why it's a duplicate. You'll also want to use [`vec!`](https://doc.rust-lang.org/std/macro.vec.html) in your real code. – Shepmaster Apr 02 '19 at 11:49

2 Answers2

2

The problem is, that your get_title method consumes the Element and therefore can only be called once. You have to accept &self as parameter instead and can do the following:

Either return a &str instead of String:

pub fn get_title(&self) -> &str {
    &self.title
}

or clone the String if you really want to return a String struct.

pub fn get_title(&self) -> String {
    self.title.clone()
}

Also have a look at these questions for further clarification:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
hellow
  • 12,430
  • 7
  • 56
  • 79
  • 1
    @cjohansson Because you tried to edit my code you also should read https://stackoverflow.com/questions/40006219/why-is-it-discouraged-to-accept-a-reference-to-a-string-string-vec-vec-o – hellow Apr 02 '19 at 07:28
  • Thanks ok, my edit worked but it wasn't best practice, didn't know about that – cjohansson Apr 02 '19 at 08:37
0

Here is a solution to the problem, it required borrowing self object and lifetime specifications.

Moving from &String to &str is only for following better practices, thanks @hellow Playground 2

struct Element<'a> {
    title: &'a str
}

impl <'a>Element<'a> {
    pub fn get_title(&self) -> &'a str {
        &self.title
    }
}

fn main() {
    let mut items: Vec<Element> = Vec::new();
    items.push(Element { title: "Random" });
    items.push(Element { title: "Gregor" });

    let mut i = 0;
    while i < 10 {
        for item in &items {
            println!("Loop {} item {}", i, item.get_title());
        }
        i = i + 1;
    }
}
cjohansson
  • 1,058
  • 10
  • 13