Split string and convert to integer

I'm starting with Rust. I have the following code, which works well, but I see it quite ugly. How can I improve this?

What I try to get is the value after: as an integer
in this case the number 2

fn main() {
    let port_data: &str = "user:2";
    let data: Vec<&str> = port_data.split(":").collect();
    println!("data split: {:?}", data);
    let card = match data.get(1) {
        Some(x) => x,
        _ => "0"
    let card: i32 = card.parse::<i32>().unwrap_or(0);
    println!("card: {}", card);


a generic solution could be:

use std::str::FromStr;

fn parse_data<T: FromStr>(s: &str, separator: char) -> Option<T> {
    match s.find(separator) {
        None => None,
        Some(index) => match T::from_str(&s[index + 1..]) {
            Ok(l) => Some(l),
            _ => None,

fn main() {
    let port_data = "user:2";
    if let Some(data) = parse_data::<i32>(port_data, ':') {
        println!("data: {:?}", data);

1 Like

I would use the ? operator and move the parsing into its own function. That way you can avoid all the match or unwrap()s.

fn get_number(text: &str) -> Option<u32> {
    // create an iterator over the pieces in our input string
    let mut words = text.split(":");

    // skip past the first word, returning None if there wasn't one
    let _user = words.next()?;

    // then save the second word to a variable
    let number = words.next()?;

    // finally, parse the number and because we don't care about the  
    // error we can use ok() to convert the Result<u32, Error> to an 
    // Option<u32>



Another way using cascading functions:

fn get_number(s: &str) -> Option<u32> 
     .map(|i| s[i+1..].parse().ok())

or using an iterator and ? as suggested by @Michael-F-Bryan

fn get_number(s: &str) -> Option<u32>
     .skip(1)    // skip "user"
     .next()?    // the ? returns None if necessary
     .parse()    // result is Result<u32,...>
     .ok()       // transforms a Result into an Option

How many answers and so fast!

Thank you. Now I'm going to review

1 Like

You could use split_once to get a pair of strings:

fn main() {
    let port_data: &str = "user:2";
    let value = port_data.split_once(":").map(|(_, v)| v).unwrap_or("0");
    let card = value.parse::<i32>().unwrap_or(0);
    println!("card: {}", card);

Even simpler:


Thanks for the answers again

I see that in all the response you used find and not split.
Actually my string comes from the reading of the serial port and it will be something similar to "A:U:V:W:X:Y:Z"
And I must get each of the values: A, U, V, etc with the correct data type according to the case.


Well then you can map over the iterator returned by split.

another solution with filter_map:

fn main() {
    let port_data = "A:10:V:120:X:37:Z:73";
    let words: Vec<_> = port_data
        .filter_map(|word| i32::from_str(word).ok())
    println!("words: {:?}", words);

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.