Pass a vector of structures by reference to a function and perform a search in it

Question:

Hello. Such a problem. You need to find the number in the vector inside the structure, which is inside the vector of these structures. Such an explanation for myself. I think the code will better show what I want to get:

struct Player
{
    name: String,
    numbers: Vec<u32>,
}

fn find_winner(players: &Vec<Player>, target_number: u32) -> Option<String>
{
    for player in players
    {
        for it in player.numbers
        {
            if it == target_number
            {
                return Some(player.name);
            }
        }
    }
    None
}

This code gives the following errors:

src\main.rs:25:13: 25:19 error: cannot move out of borrowed content
src\main.rs:25          for it in player.numbers
                                  ^~~~~~
note: in expansion of for loop expansion
src\main.rs:25:3: 31:4 note: expansion site
note: in expansion of for loop expansion
src\main.rs:23:2: 32:3 note: expansion site
src\main.rs:29:17: 29:23 error: cannot move out of borrowed content
src\main.rs:29                          return Some(player.name);
                                                    ^~~~~~

What is the problem and how can I fix this code? Thanks!

> rustc --version
rustc 1.2.0 (082e47636 2015-08-03)

Answer:

In Rust, for non-basic types, let a = b; means moving the value of variable b to variable a . After the move, access to b not possible – the lifetime of the variable has expired. If at the time of moving to the variable b there is an active link, then an error will occur.

Here's a simple example to illustrate:

#[derive(Debug)]
struct Foo{
    val:u32
}

fn main() {

    let a = Foo{val:42};
    let refa = &a;
    let c = a;
    println!("{:?}",c);
}

<anon>:31:9: 31:10 error: cannot move out of `a` because it is borrowed
<anon>:31     let c = a;
                  ^
<anon>:30:17: 30:18 note: borrow of `a` occurs here
<anon>:30     let refa = &a;

If by the time the value is moved, the refa lifetime refa , then the move let c = a becomes valid:

fn main() {

    let a = Foo{val:42};
    {
        let refa = &a;
    }
    let c = a;
    println!("{:?}",c);
}

About Rust ownership : http://kgv.github.io/rust_book_ru/src/ownership.html


In your example, the second loop moves the value to which the active reference exists. One reference is taken when the function is called, another one in the first loop. The solution is to make a second loop over references, not over values.

The return value is the same. Rust will not allow moving the value while there is a live link to it. Better to return a link to the string (slice).

Here is the working code:

fn find_winner(players: &Vec<Player>, target_number: u32) -> Option<&str>
{
    for player in players
    {
        for it in &player.numbers
        {
            if *it == target_number
            {
                return Some(&player.name);
            }
        }
    }
    None
}
Scroll to Top