0

I want to write a program that sets the shell for the system's nslookup command line program:

fn main() {
    let mut v: Vec<String> = Vec::new();
    let mut newstr = String::from("nslookup");
    for arg in std::env::args() {
        v.push(arg);
        newstr.push_str(&format!(" {}", arg));
    }
    println!("{:?}", v);
    println!("{}", newstr);
}
error[E0382]: borrow of moved value: `arg`
 --> src/main.rs:6:41
  |
5 |         v.push(arg);
  |                --- value moved here
6 |         newstr.push_str(&format!(" {}", arg));
  |                                         ^^^ value borrowed here after move
  |
  = note: move occurs because `arg` has type `std::string::String`, which does not implement the `Copy` trait

How to correct the code without traversing env::args() again?

trent
  • 25,033
  • 7
  • 51
  • 90
tantalum
  • 13
  • 8

2 Answers2

2

Reverse the order of the lines that use arg:

for arg in std::env::args() {
    //newstr.push_str(&format!(" {}", arg));
    write!(&mut newstr, " {}", arg);
    v.push(arg);
}

Vec::push takes its argument by value, which moves ownership of arg so it can't be used anymore after v.push(arg). format! and related macros implicitly borrow their arguments, so you can use arg again after using it in one of those.

If you really needed to move the same String to two different locations, you would need to add .clone(), which copies the string. But that's not necessary in this case.

Also note that format! creates a new String, which is wasteful when all you want is to add on to the end of an existing String. If you add use std::fmt::Write; to the top of your file, you can use write! instead (as shown above), which is more concise and may be more performant.

See also

trent
  • 25,033
  • 7
  • 51
  • 90
1

You can do like that:

fn main() {
    let args: Vec<_> = std::env::args().collect();
    let s = args.join(" ");

    println!("{}", s);
}

First, you create the vector, and then you create your string.

Boiethios
  • 38,438
  • 19
  • 134
  • 183