2
votes

I have a struct like this with some parsed arguments:

struct Args {
    out: Option<String>,
    version: bool,
    help: bool,
    files: Vec<String>,
}

I want to recursively parse a list, returning a new modified Args struct every time I need to modify it:

fn parse(parsed: &Args, start: usize, args: Vec<String>) -> Args {
    if start >= args.len() {
        return parsed.clone();
    }

    if args[start] == "--version" {
        return parse(&Args { version: true, ..parsed.clone() }, start + 1, args);
    }
    if args[start] == "--help" {
        return parse(&Args { help: true, ..parsed.clone() }, start + 1, args);
    }
    return Args { files: args[start..args.len()].to_vec(), ..parsed.clone() };
}

I use the function like this:

fn main() {
    let args = std::env::args().collect::<Vec<String>>();
    let parsed = parse(&Args::default(), 1, args);
}

This code works, but I would like to type:

return parse(&Args { version: true, ..parsed }, start + 1, args);

instead of:

return parse(&Args { version: true, ..parsed.clone() }, start + 1, args);

to avoid excessive data copying during cloning. When I just remove .clone() it says that Args type expected but it got &Args instead.

When I dereference with *parsed compiler says "cannot move out of borrowed content"

1
Have you considered not passing the parsed argument by reference? - loganfsmyth
@loganfsmyth Yep, that's how I ended up. The speed gain for not cloning I got is about 7%. - konmik

1 Answers

2
votes

When a type T is Clone then invoking clone() on a &T will also return a T, because there's no point just copying the pointer. In fact, if it did clone the underlying data and then returned a reference to it then you'd run into trouble because the T would get dropped, leaving the pointer dangling.

To turn a &T into a T, you can use the * operator to dereference it. However, this is going to give you problems because parsed is borrowed by the parse function, which means it has to give it back when it's finished. If you dereference it and move the values then you'll be moving out of a borrowed context.