0

I am trying to learn Rust, and am trying to write a simple program that takes arguments from the command line, to get used to some basic concepts. The code I wrote to handle the arguments, fails, and I feel like I am missing some basic concept.

fn process_args(args: Vec<String>) {
    let my_string: String = String::from("--verbose");
    for item in &args[1..]    {
        match item{
            my_string=>do_something_with_argument(),
            _=>println!("unexpected argument {item}"),
        }
    }
}

Where vscode tells me that the 'my_string', variable is unused. I also tried this version:

fn process_args(args: Vec<String>) {
    for item in &args[1..]    {
        match item{
            "--verbose"=>do_something_with_argument(),
            _=>println!("unexpected argument {item}"),
        }
    }
}

which fails because the string literal cannot be matched with a string, then I tried:

fn process_args(args: Vec<String>) {
    for item in &args[1..]    {
        match item{
            String::from("--verbose")=>do_something_with_argument(),
            _=>println!("unexpected argument {item}"),
        }
    }
}

Which also does not work.

What am I missing. I feel like they all should work.

fish
  • 168
  • 5

1 Answers1

1

The left hand side of a "match" arm is a pattern. If you have a name in a pattern, it's an implicit declaration. So in the first version, the first arm is just a pattern for any value, binding it to the (new) local variable my_string. Some languages (e.g. erlang) can dereference variables in patterns, Rust can't.

The third version can not work, because a function call is not a valid pattern.

The second version actually nearly works if you bother to read the compiler error:

error[E0308]: mismatched types
 --> src/lib.rs:4:13
  |
3 |         match item {
  |               ---- this expression has type `&String`
4 |             "--verbose" => {},
  |             ^^^^^^^^^^^ expected `&String`, found `&str`
  |
  = note: expected reference `&String`
             found reference `&'static str`

item is an &String, but the pattern only matches &str, so all you need to do is make the two match by "converting" item to an &str, via String::as_str or &** for instance:

fn process_args2(args: Vec<String>) {
    for item in &args[1..]    {
        match &**item {
            "--verbose" => {},
            _=>println!("unexpected argument {item}"),
        }
    }
}

Although I would also say that this is not very useful, you're testing flags for equality, why don't you just... test flags for equality? Using ==? It's not like Rust can construct a jump table from strings.

Masklinn
  • 34,759
  • 3
  • 38
  • 57
  • Thank you! I mostly did it this way for learning purposes, irrespective of its effectiveness. I did not realise that str and String were different types O_o, so thank you for clarifying this, so that I can keep learning. – fish Aug 25 '23 at 15:53
  • Oh boy if you hadn't realised String and str are different things you're in for a treat, Rust has like 6 string types just in the stdlib. – Masklinn Aug 25 '23 at 17:11
  • Oh wow... This is going to be interesting :D – fish Aug 26 '23 at 14:16