3

How can I check a variable (entered by user) is a number such as an int, float, or something else?

I want to do this with a match expression:

let mut input = String::new();
io::stdin().read_line(&mut input);
let result = match input {
    // !!??     
}

is it possible by match?

5
  • It is a very bad idea to ignore the Result returned from read_line. Commented Nov 22, 2016 at 16:05
  • @Shepmaster: "very" is relative, in a one-off script it may not matter :) Commented Nov 22, 2016 at 16:07
  • @MatthieuM. nah, I'll be an extremist in this case: it's never acceptable to ignore errors. It's a simple thing to handle the error (.expect("Could not read input")). For a one-off script, I agree that aborting is a reasonable way to handle the error, as opposed to something more user-friendly. Commented Nov 22, 2016 at 16:09
  • I agree with @Shepmaster - unwrap() is trivial to write even in a one-off script, and it can save you serious pain in cases where the error would have otherwise gone undetected. Commented Nov 22, 2016 at 16:21
  • @user4815162342 and I'll always advocate for expect over unwrap, just so when the failure occurs it's much easier to find it. Commented Nov 22, 2016 at 16:28

1 Answer 1

7

If you want to match against something then you need something to destructure on. You can match against string slices, but only a finite set, so that doesn't help here.

So let's have an enum to match on:

enum Value {
    Int(isize),
    Float(f64),
}
use Value::*;  // Make the variants available without Value::

Then you need to parse the string into the appropriate type. You can use the parse method for each type (if you're happy with Rust's syntax for those; otherwise you might need a fancier parser):

fn parse_string(s: &str) -> Option<Value> {
    if let Ok(i) = s.parse() {  // inferred as isize from next line
        Some(Int(i))
    } else if let Ok(f) = s.parse() {
        Some(Float(f))
    } else {
        None
    }
}

Note that when trying parses in sequence like this the order matters; "123" would parse as an f64 too.

I'm turning any parse errors into None and using Option rather than Result because it's not clear what the error would be (since each parse can return its own); in a real application I might have a ParseError type.

Now we can match on the result:

fn main() {
    let x = "123";
    match parse_string(x) {
        Some(Int(i)) => println!("int {}", i),
        Some(Float(f)) => println!("float {}", f),
        None => println!("Didn't parse"),
    }
    let x = "123.5";
    match parse_string(x) {
        Some(Int(i)) => println!("int {}", i),
        Some(Float(f)) => println!("float {}", f),
        None => println!("Didn't parse"),
    }
}

Runnable playground link

Sign up to request clarification or add additional context in comments.

1 Comment

The inference in those if let bindings is quite extraordinary. I mean that in a good way - I learned something from this. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.