2

I'm trying to store a string (or str) of digits, e.g. 12345 into a vector, such that the vector contains {1,2,3,4,5}.

As I'm totally new to Rust, I'm having problems with the types (String, str, char, ...) but also the lack of any information about conversion.

My current code looks like this:

fn main() {
    let text = "731671";                
    let mut v: Vec<i32>;
    let mut d = text.chars();
    for i in 0..text.len() {
        v.push( d.next().to_digit(10) );
    }
}
dani
  • 3,267
  • 3
  • 21
  • 49
  • 1
    [Food for thought](https://play.rust-lang.org/?gist=76795197b5c0200b31bc86167f13cc94&version=stable&backtrace=1) – ildjarn Apr 20 '17 at 10:21

3 Answers3

7

You're close!

First, the index loop for i in 0..text.len() is not necessary since you're going to use an iterator anyway. It's simpler to loop directly over the iterator: for ch in text.chars(). Not only that, but your index loop and the character iterator are likely to diverge, because len() returns you the number of bytes and chars() returns you the Unicode scalar values. Being UTF-8, the string is likely to have fewer Unicode scalar values than it has bytes.

Next hurdle is that to_digit(10) returns an Option, telling you that there is a possibility the character won't be a digit. You can check whether to_digit(10) returned the Some variant of an Option with if let Some(digit) = ch.to_digit(10).

Pieced together, the code might now look like this:

fn main() {
    let text = "731671";
    let mut v = Vec::new();
    for ch in text.chars() {
        if let Some(digit) = ch.to_digit(10) {
            v.push(digit);
        }
    }
    println!("{:?}", v);
}

Now, this is rather imperative: you're making a vector and filling it digit by digit, all by yourself. You can try a more declarative or functional approach by applying a transformation over the string:

fn main() {
    let text = "731671";
    let v: Vec<u32> = text.chars().flat_map(|ch| ch.to_digit(10)).collect();
    println!("{:?}", v);
}
Community
  • 1
  • 1
ArtemGr
  • 10,505
  • 2
  • 46
  • 78
3

ArtemGr's answer is pretty good, but their version will skip any characters that aren't digits. If you'd rather have it fail on bad digits, you can use this version instead:

fn to_digits(text: &str) -> Option<Vec<u32>> {
    text.chars().map(|ch| ch.to_digit(10)).collect()
}
fn main() {
    println!("{:?}", to_digits("731671"));
    println!("{:?}", to_digits("731six71"));
}

Output:

Some([7, 3, 1, 6, 7, 1])
None
notriddle
  • 610
  • 4
  • 10
0

New version of Rust

Returns an Enum if conversion to digit fails.

#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidDigit(char),
}


fn to_digits(text: &str) ->  Result<Vec<u32>, Error> {

    let mut numbers = Vec::new();
    for s in string_digits.chars(){

        match s.to_digit(10){
            Some(number) => numbers.push(number),
            None => {return Err(Error::InvalidDigit(s));}
        }
    Ok(numbers)
    }
GraphicalDot
  • 2,107
  • 1
  • 22
  • 40