Hi, this is the source of char::to_digit():
pub fn to_digit(self, radix: u32) -> Option<u32> {
assert!(radix <= 36, "to_digit: radix is too high (maximum 36)");
// the code is split up here to improve execution speed for cases where
// the `radix` is constant and 10 or smaller
let val = if radix <= 10 {
match self {
'0'..='9' => self as u32 - '0' as u32,
_ => return None,
}
} else {
match self {
'0'..='9' => self as u32 - '0' as u32,
'a'..='z' => self as u32 - 'a' as u32 + 10,
'A'..='Z' => self as u32 - 'A' as u32 + 10,
_ => return None,
}
};
if val < radix { Some(val) } else { None }
}
I'd like to know why it isn't more like this:
pub fn to_digit(self, radix: u8) -> Option<u8> {
if radix > 36 { return None; }
// the code is split up here to improve execution speed for cases where
// the `radix` is constant and 10 or smaller
let val = if radix <= 10 {
match self {
'0' ..= '9' => self as u8 - b'0',
_ => return None,
}
} else {
match self {
'0' ..= '9' => self as u8 - b'0',
'a' ..= 'z' => self as u8 - b'a' + 10,
'A' ..= 'Z' => self as u8 - b'A' + 10,
_ => return None,
}
};
if val < radix { Some(val) } else { None }
}
That can be used as:
fn main() {
println!("{:?}", '8'.to_digit(10));
let a = [10, 20];
if let Some(d) = '1'.to_digit2(10) {
println!("{:?}", a[usize::from(d)]);
}
}
There are few differences:
- Instead of a panic, it returns None if radix > 36.
- It contains less "as" casts.
- It returns an optional u8, this is handy because you can convert it safely and losslessly (avoiding "as" in user code) using ::from() without "as" casts to usize, u32 and some other types.
What do you think?