Match case review, for new user

Hello all, I am very new to Rust. I am currently building a command line program, and the only way for me to capture typed user sentences i.e., "the quick brown fox", as a vector and check for specific words in specific indexes. For instance, I want to make sure the first word is taken into consideration and something happens. Below is the code I am currently using, and its the only way I was able to get the code to match and do specific actions based upon my criteria. Please review and tell me if this is the proper way to format it, as it seems off to me. Appreciate any and all suggestions.

use std::io::stdout;
use std::io::stdin;
use std::io::Write;

fn main() {
loop {
    print!("[Rust] >> ");
    stdout().flush();

    let mut input = String::new();
    stdin().read_line(&mut input).unwrap();
    input.pop();

    let mut v: Vec<String> = Vec::new();

    let command = input.split(" ");
    for x in command {
        v.push(x.to_string());
    }
    if v.len() > 3 {
        println!("Too many arguments.");
    } else {
    // currently this else part is just a placeholder.
    println!("{:?}", v);
    }

    // Here comes the part I think is not the best syntax??
    match v {
        _ if &v[0].to_lowercase() == "1" => println!("You typed in the number 1."),
        _ if &v[0].to_lowercase() == "2" => println!("You typed in the number 2."),
        _ if &v[0].to_lowercase() == "3" => println!("You typed in the number 3."),
        _ if &v[0].to_lowercase() == "4" => println!("You typed in the number 4."),
        _ if &v[0].to_lowercase() == "5" => println!("You typed in the number 5."),
        _ if &v[0].to_lowercase() == "6" => println!("You typed in the number 6."),
        _ if &v[0].to_lowercase() == "cheese" => println!("Your first word was 'cheese'."),
        _ if &v[0].to_lowercase() == "plate" => println!("Your first word is 'plate'."),
        _ => println!("Didn't catch it."),
    };
}

To print Didn't catch it. this code allocates 8 temporary Strings of same text which is not super efficient. But the real problem is it's too verbose. You can at least write it like this:

    match &v[0].to_lowercase()[..] {
        "1" => println!("You typed in the number 1."),
        "2" => println!("You typed in the number 2."),
        "3" => println!("You typed in the number 3."),
        "4" => println!("You typed in the number 4."),
        "5" => println!("You typed in the number 5."),
        "6" => println!("You typed in the number 6."),
        "cheese" => println!("Your first word was 'cheese'."),
        "plate" => println!("Your first word is 'plate'."),
        _ => println!("Didn't catch it."),
    }
1 Like

Hey, thanks for your comment. I originally tried it just as that, but it would fail to compile. "Expecting struct string, given str".

Edit: I did not have the [..]. What does this do?

The [..] converts String to str.

1 Like

Lol omg, I looked all over Google, "how to convert string to str in rust". Got a lot of good stuff, but nothing specific to my use case.

Thank you for that information! I knew there had to be something, because it felt very "blah".

This is not specific to your use case though. The &string[..] trick works everywhere, but there are a bunch of other, more discoverable/obvious ways:

  • Using the inherent method the_string.as_str() is the most direct one
  • The AsRef trait: the_string.as_ref()
  • By explicitly borrowing: the_string.borrow()
  • Via a Deref corecion: &*the_string
3 Likes

You might be interested in a feature called "slice patterns". A while back, I wrote up an article walking through how it works and one of the examples does almost exactly what you are trying to do.

You do something like this to create a Vec<&str>where each &str points to a word in the original input:

fn main() {
    let mut input = String::new();
    std::io::stdin().read_line(&mut input).unwrap();
    
    let words: Vec<&str> = input.split_whitespace().collect();

    let args = parse_args(&words);
    println!("{args:?}");
}

As well as being simpler than the version with manual pop()s and push()es, it's also more efficient because we only ever create one owned string (input) and our words just reference parts of that string.

2 Likes

Thank you for this comment Michael. I will be looking into this, as it seems this is way better suited for my particular use case. Want the code to work, but also be efficient. So thank you for providing this information.

1 Like

It's worth mentioning that it probably takes longer for the printed output to be sent to your terminal's process and rendered to the screen than it does to run that whole example to finish.

So while it's nice to avoid unnecessary string copies when you can (like we did there), there's no need to bend over backwards to avoid them... Your bottlenecks are almost always elsewhere, and modern computers are fast!

3 Likes

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.