elleciel
elleciel

Reputation: 2587

What is the cleanest way to convert &str types to numeric types?

I find myself reading large CSV files and collecting the numerical elements into a Vec<&str>. Thereafter I have to convert them to numeric types and the simplest way I've found to do that is to implement a function like this:

fn to_u32(str: &str) -> u32
{
    let str_num: Option<u32> = str.parse();
    match str_num
    {
        Some(num) => num,
        None      => panic!("Failed to read number"),
     }
 }

This seems like a fairly common operation so I've sifted through the reference docs but haven't found anything that matches it. Is there a cleaner way to do this?

Upvotes: 1

Views: 137

Answers (2)

huon
huon

Reputation: 102256

The Option type has a large variety of adapter methods which can be used to munge the data around more nicely than repeated matchs.

For example, there's unwrap and expect for just extracting the data out of a Some, panicking if the Option is None. The expect method is actually the closest to your written code: str.parse().expect("Failed to read number.").


However, it can often makes sense to use other the functions listed there, to propagate errors, avoiding the hard "crash" of a panic and allowing users (or yourself) to handle errors more centrally and with more control. It also often makes sense to use Result for this, which gives you the chance to pass along more information in the error case, and also allows one to use the try! macro, that said, one can easily define an equivalent of try! for Option:

macro_rules! option_try {
    ($e: expr) => {
        match $e {
            Some(x) => x,
            None => return None
        }
    }
}

Upvotes: 4

Vladimir Matveev
Vladimir Matveev

Reputation: 128081

Well, you can use unwrap() to avoid pattern matching, but you should do it sparingly - with unwrap() you can't handle the actual parse error, so if the string does not represent a number, it'll panic:

let str_num: u32 = str.parse().unwrap();

if let is also an option:

if let Some(str_num) = str.parse::<u32>() {
    // ...
}

You can also use unwrap_or() if you want to specify some default value:

let str_num: u32 = str.parse().unwrap_or(42);

Or you can use unwrap_or_default() which employs Default instance for u32:

let str_num: u32 = str.parse().unwrap_or_default();

Upvotes: 2

Related Questions