<Option<Vec<u64>>> from char.to_digit

I've got a start on a Luhn algorithm that takes a credit card number as string, as an impl of Digits trait

impl Digits for String {
    fn digits(self) -> Result<Vec<u32>, String> {
        self.chars()
            .map(|c| c.to_digit(10))
            .collect::<Option<Vec<u32>>>()
            .ok_or("Invalid Digits".to_string())
    }
}

pub trait Digits {
    fn digits(self) -> Result<Vec<u32>, String>;
}

It works, but I'm now trying to create trait implementation that allows me to pass an integer instead of a string. The problem I'm running into is that since

let ex2 = 4539148803436467; is literal out of range for u32

I need to let ex2: u64 = 4539148803436467;, which requires refactoring the Digits trait to return a result with Vec<u64>.

Obviously there are ways I can refactor that don't require me refactor the trait to

pub trait Digits {
    fn digits(self) -> Result<Vec<u64>, String>;
}

But now I'm curious to how I would do it. I've tried various ways of converting u32 to u64 for

        .map(|c| c.to_digit(10))
        .collect::<Option<Vec<u32>>>()

but I can't seem to figure it out.

.map(From::from) will convert iterated elements (it's same as .map(|x| x.into())).

1 Like
c.to_digit(10).map(u64::from)

will convert the Option<u32> from to_digit into a Option<u64>

1 Like

thank you. i knew there was a simple way

thank you. nice and simple.

Can somebody please explain why that line works? char::to_digit returns an Option, but I thought you only can collect a Vec<Option<u32>>. How does it behave if one digit cannot be converted? Does it then early out? Is there any documentation for this?

An iterator of Options can be collected into an Option of a collection. If one of the options is None, the method stops early and returns None. The documentation for that is here.

Similarly, you can .collect() an Iterator<Item=Result<T, E>> into a Result<Vec<T>, E> and the method would stop at the first error. This is made possible by just the same trait.

5 Likes