2

I am doing some simple stuff with rust... just touching some ground you know.

So I was playing with command line arguments, and I can't go past this:

use std::os::args;

fn main(){

    let arg1 = args().get(1).to_str();

    let help_command = "help";

    if args().len() == 1 {
            println!("No arguments.");
    }

    else if args().len() == 2 {

            match arg1 {
                    help_command => println!("Do ..."),
                    _    => println!("no valid argument")
            }

    }

}

I can't compile... The error is:

main.rs:17:4: 17:5 error: unreachable pattern
main.rs:17                      _    => println!("no valid argument")
                                ^
error: aborting due to previous error

Also, I am using Rust 0.11.0-pre-nightly.

EDIT: Also, if I go with this approach:

match arg1 { 
    "help" => { /* ... / }, 
    _ => { / ... */ }, 
}

It throws another error:

error: mismatched types: expected collections::string::String but found &'static str (expected struct collections::string::String but found &-ptr) 
Carlos Cavero
  • 3,011
  • 5
  • 21
  • 41
  • As an aside, there are some really nice existing libraries for parsing command line arguments (although I appreciate in this instance you might be looking to do it yourself just for the experience). Docopt (https://github.com/docopt/docopt.rs) is a really nice one in which you just have to write the "man" help text and it will automagically parse your command arguments for you. Clap (https://github.com/kbknapp/clap-rs) has a more traditional structure. – Drgabble Aug 23 '17 at 15:16

1 Answers1

5

You can't use variables on Rust's match patterns. The code is being interpreted as binding whatever value is on arg1 as a new variable called help_command, and thus the catch-all pattern never matches.

You can use the literal string to match arg1:

match arg1 {
    "help" => { /* ... */ },
    _      => { /* ... */ },
}

Or use a guard:

match arg1 {
    command if command == help_command => { /* ... */ },
    _ => { /* ... */ }
}

If you are concerned about the type safety and/or repetition with using strings directly, you can parse the command into an enum:

enum Command {
    HelpCommand,
    DoStuffCommand
}

fn to_command(arg: &str) -> Option<Command> {
    match arg {
        "help"     => Some(HelpCommand),
        "do-stuff" => Some(DoStuffCommand),
        _          => None,
    }
}

Working example

Update (thanks @ChrisMorgan): It is also possible to use a static variable:

static HELP: &'static str = "help";

match arg1 {
    HELP => { /* ... */ },
    _ => { /* ... */ },
}

About the error reported in the question edit: Rust has two kinds of strings: &str (string slice) and String (owned string). The main difference is that the second is growable and can be moved. Refer to the links to understand the distinction better.

The error you are encountering is due to the fact that string literals ("foo") are of type &str, while std::os::args() is a Vec of String. The solution is simple: Use the .as_slice() method on the String to take slice out of it, and be able to compare it to the literal.

In code:

match arg1.as_slice() {
    "help" => { /* ... */ },
    _      => { /* ... */ },
}
Renato Zannon
  • 28,805
  • 6
  • 38
  • 42
  • Thanks for your answer, but thats where things start to be complicated. I took this approach, because using that example: "match arg1 { "help" => { /* ... */ }, _ => { /* ... */ }, }" throws another error. "error: mismatched types: expected `collections::string::String` but found `&'static str` (expected struct collections::string::String but found &-ptr) " – Romeu Vieira Jul 29 '14 at 01:56
  • Can you update the question with the error? – Renato Zannon Jul 29 '14 at 01:56
  • @RomeuVieira does the updated answer help? – Renato Zannon Jul 29 '14 at 02:06
  • 1
    Thank you for the awesome explanation! I am more used to higher level stuff, but determined to get into lower level programming. Thank you again! – Romeu Vieira Jul 29 '14 at 02:08
  • 1
    You can also use a static, e.g. `static HELP: &'static str = "help"` and `HELP => …`. – Chris Morgan Jul 29 '14 at 02:21
  • @ChrisMorgan oh nice, I didn't know that! Will update the answer – Renato Zannon Jul 29 '14 at 02:29