Why "move occurs"

I have an function param of type args: & std::env::Args, marked in bold in the code:
During the compilation compiler complains about line marked as 1)

pub struct Config<'a>{
    pub program_name: &'a String,
    pub query: &'a String,
    pub file_name: &'a String,
}

impl<'a> Config<'a> {
    **pub fn new(args: & std::env::Args)** -> Result<Config, &'static str> 
    {
        if args.count() < 3 {**1) ^^^^ move occurs because `*args` has type `std::env::Args`, which does not implement the `Copy` trait**
            return Err("Not enough arguments provided");
        }
        Ok(Config {
            program_name: &args.next().unwrap(),
            query: &args.next().unwrap(),
            file_name: &args.next().unwrap(),
        })
    }
}

I really don't understand why would move occur? I'm merely taking the count of the elements, so "in theory" I shouldn't be moving anything and yet apparently I'm moving? Why, and how to fix it?

Thanks

Please check out our post on formatting guidelines. In particular, please use a code block instead of a quote block.

Which button ^^^ on the toolbar is for the code formatting?

You can do it by surrounding the text by three backticks like this:

```
fn main() {
    println!()
}
```

Could you please tell me which button ^^^ on the toolbar is for the code formatting?
I'm asking because I don't have that char on my keyboard so I'd like to be able to use the tools provided by this forum.

Hmm, it appears to be missing. There's the </> button which indents by four spaces, but then you don't get syntax highlighting.

Edit: You can also use the ~ symbol.

1 Like

Thanks, indeed ~ helps.
But tbh, not having it on the toolbar is somewhat funny...

The error occurs because the count method consumes the iterator it is called on. Additionally, your calls to .next() will also fail to compile as you don't have mutable access to the Args iterator, since asking for the next item requires mutating the iterator.

You probably want to something like this:

pub struct Config {
    pub program_name: String,
    pub query: String,
    pub file_name: String,
}

impl Config {
    pub fn new(args: &[String]) -> Result<Config, &'static str> 
    {
        if args.len() < 3 {
            return Err("Not enough arguments provided");
        }
        Ok(Config {
            program_name: args[0].clone(),
            query: args[1].clone(),
            file_name: args[2].clone(),
        })
    }
}
let args = std::env::args().collect::<Vec<_>>();
let config = Config::new(&args);

I agree about the button. I've never really thought about it before.

This uses the collect function to turn the iterator into a vector.

1 Like

Thanks, I appreciate that help.
The only thing I'm not happy about it is that there is a cloning used, which "theoretically" shouldn't be needed as the "env::args" won't go out of scope until main exits.

If you really want to avoid it, then you’d need to take a mutable reference to the iterator, since progressing through an iterator requires mutating it

impl<'a> Config<'a> {
    pub fn new(args: &mut std::env::Args) -> Result<Config, &'static str> 
    {
        Ok(Config {
            program_name: args.next().ok_or(“not enough arguments”)?,
            query: args.next().ok_or(“not enough arguments”)?,
            file_name: args.next().ok_or(“not enough arguments”)?,
        })
    }
}

Edit: this code is broken. It should work in principle, but I haven’t tried it, and anyway the smartphone keyboard gave me curly quotes.

O yes, that's actually beautiful, I especially like the usage of ok_or.

Another tip is that you don't want references in your Config struct. I removed them in my example, but just to point it out:

pub struct Config {
    pub program_name: String,
    pub query: String,
    pub file_name: String,
}

If you use references in the above, then the Config struct would not have ownership of the variables, and some other value would have to actually store the strings. As you can see in @notriddle's example, you can still avoid the clone even when not using references.

Yes, I agree with that.

You can just take the Vec by value, and then you can both access its .len() without consuming it, and then also remove elements from it one-by-one (eg. using into_iter() or pop() or swap_remove() etc.)

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.