Arny
Arny

Reputation: 13

cannot move out of borrowed content when iterating the loop

I'm trying to get field from my structure in rust

fn check_args(command: i32, args: Vec<String>) -> Vec<Argument> {
    let arg_tbl: [ArgsTable; 5] = [
        ArgsTable { cc: 0, ac: 1, dv: "4".to_string() },
        ArgsTable { cc: 1, ac: 1, dv: "4".to_string() },
        ArgsTable { cc: 1, ac: 2, dv: "in.txt".to_string() },
        ArgsTable { cc: 4, ac: 3, dv: "1".to_string() },
        ArgsTable { cc: 6, ac: 2, dv: "out.txt".to_string() },
    ];
    let mut arguments: Vec<Argument> = Vec::new();
    if args.len() == 0 {
        for arg in arg_tbl.iter() {
            if arg.cc == command {
                arguments.push(Argument {
                    code: arg.ac,
                    value: arg.dv,
                });
            }
        }
    }
}

but get this error

    |
151 |                     value: arg.dv
    |                            ^^^ cannot move out of borrowed content

How can I get the arg.dv field?

Upvotes: 0

Views: 4249

Answers (1)

wimh
wimh

Reputation: 15232

Although you already have an answer, I will explain the problem and provide a different solution too. I also recommend reading Effectively Using Iterators In Rust.

I'll start with a MCVE, which you can test on the playground too:

struct ArgsTable {
    dv: String,
}

fn check_args() -> Vec<ArgsTable> {
    let arg_tbl: [ArgsTable; 2] = [
        ArgsTable {
            dv: "4".to_string(),
        },
        ArgsTable {
            dv: "out.txt".to_string(),
        },
    ];
    let mut arguments: Vec<ArgsTable> = Vec::new();
    for arg in arg_tbl.iter() {
        arguments.push(ArgsTable { dv: arg.dv });
    }
    arguments
}

fn main() {
    check_args();
    println!("Hello, world!");
}

This uses arg_tbl.iter(), which will borrow from arg_tbl. String does not implement the Copy trait, so it can't be copied into arguments. Because it is borrowed, it can also not be moved. That causes the error message cannot move out of borrowed content. Because String does implement Clone, you can clone it to get a copy. That is why adding a clone() on line 13 fixes the problem.

It is also possible to fix this using an iterator which does not borrow; into_iter. But by-value iterators for arrays are not available at the moment. If you use arg_tbl.into_iter(), the array will dereference into a slice, and you will still iterate by reference! But if you change the array into a Vec, it will work without having to clone:

let arg_tbl = vec![
    ArgsTable {
        dv: "4".to_string(),
    },
    ArgsTable {
        dv: "out.txt".to_string(),
    },
];
let mut arguments: Vec<ArgsTable> = Vec::new();
for arg in arg_tbl.into_iter() {
    arguments.push(ArgsTable { dv: arg.dv });
}

You can now also simplify the for loop like this:

for arg in arg_tbl {

Upvotes: 7

Related Questions