Problem.
I'm curious about this because if it can, I don't need if thing in this code I think.
I want that especially .filter_map(|ch| ch.to_digit(10))
.
ch.to_digit()
returns None if ch is not digit. then I want return false.
If I can do this, I think I don't need if !code.chars().all(|ch| ch.is_digit(10) || ch.is_whitespace())
this check.
(I just wanted to know can I do that if checks within chaining.)
If it's not allowed, is there some way to do exception check in function chain?
Thanks.
/// Check a Luhn checksum.
pub fn is_valid(code: &str) -> bool {
if code.trim().len() <= 1 {
return false;
}
if !code.chars().all(|ch| ch.is_digit(10) || ch.is_whitespace()) {
return false;
}
code.chars()
.rev()
.filter_map(|ch| ch.to_digit(10))
.enumerate()
.map(|( i, n)|
match i % 2 {
0 => n,
_ if n == 9 => n,
_ => (n * 2) % 9,
}
)
.sum::<u32>() % 10 == 0
}
CodePudding user response:
You can with try_fold
:
pub fn is_valid(code: &str) -> bool {
code.chars()
.rev()
.try_fold((0, 0), |acc, ch|
// `acc.0` enumerates the valid digits
// `acc.1` accumulates the sum
if ch.is_whitespace() {
Some (acc)
} else {
ch.to_digit (10).map (|n|
match acc.0 % 2 {
0 => (acc.0 1, acc.1 n),
_ if n == 9 => (acc.0 1, acc.1 n),
_ => (acc.0 1, acc.1 (n*2)%9),
})
})
.map (|acc| acc.1 % 10 == 0)
.unwrap_or (false)
}
However for readability's sake, I would go with @Masklinn's straightforward for
loop.
CodePudding user response:
Can I return immediately when meets None while function chaining?
Not really. You could map
to an Option
(instead of filter_map
) then collect
the Iterator<Option<_>>
to an Option<Vec<_>>
:
let items = vec![0_u16, 1, 2];
let res: Option<Vec<u16>> = items
.iter()
.map(|x| x.checked_add(1))
.collect();
assert_eq!(res, Some(vec![1, 2, 3]));
let res: Option<Vec<u16>> = items
.iter()
.map(|x| x.checked_sub(1))
.collect();
assert_eq!(res, None);
then you'd bail if you have a None
at the end.
But in all honestly I'd just use a bog-standard for
loop e.g.:
let mut sum = 0;
for (i, n) = code.chars().rev().map(|ch| ch.to_digit(10)).enumerate() {
sum = match (i % 2, n) {
(_, None) => return false;
(0, Some(n)) => n,
(_, Some(9)) => 9,
(_, Some(n)) => (n * 2) % 9,
}
}
sum % 10 == 0
If it's not allowed, is there some way to do exception check in function chain?
Not sure what you mean.