Luhn From
1. Readme
来自 Luhn
Luhn:使用 From Trait
在做这个练习之前,你应该做原始的 LuHn 练习。如果您还没有完成 Luhn,您可以通过运行命令来获得它:
exercism download --exercise=luhn --track=rust
在原始的 LuHn 练习中,您只验证字符串,但 Luhn 算法也可以应用于整数。
在本练习中,您将实现From trait,用来将字符串、strs 和无符号整数转换为执行验证的结构。
资源
The Rust track maintainers,基于原始 Luhn 练习
2. 开始你的表演
pub struct Luhn; impl Luhn { pub fn is_valid(&self) -> bool { unimplemented!("Determine if the current Luhn struct contains a valid credit card number."); } } /// Here is the example of how the From trait could be implemented /// for the &str type. Naturally, you can implement this trait /// by hand for the every other type presented in the test suite, /// but your solution will fail if a new type is presented. /// Perhaps there exists a better solution for this problem? impl<'a> From<&'a str> for Luhn { fn from(input: &'a str) -> Self { unimplemented!("From the given input '{}' create a new Luhn struct.", input); } }
3. 测试代码查看
# #![allow(unused_variables)] #fn main() { #[test] fn you_can_validate_from_a_str() { let valid = Luhn::from("046 454 286"); let invalid = Luhn::from("046 454 287"); assert!(valid.is_valid()); assert!(!invalid.is_valid()); } #[test] //#[ignore] fn you_can_validate_from_a_string() { let valid = Luhn::from(String::from("046 454 286")); let invalid = Luhn::from(String::from("046 454 287")); assert!(valid.is_valid()); assert!(!invalid.is_valid()); } #[test] //#[ignore] fn you_can_validate_from_a_u8() { let valid = Luhn::from(240u8); let invalid = Luhn::from(241u8); assert!(valid.is_valid()); assert!(!invalid.is_valid()); } #[test] //#[ignore] fn you_can_validate_from_a_u16() { let valid = Luhn::from(64_436u16); let invalid = Luhn::from(64_437u16); assert!(valid.is_valid()); assert!(!invalid.is_valid()); } #[test] //#[ignore] fn you_can_validate_from_a_u32() { let valid = Luhn::from(46_454_286u32); let invalid = Luhn::from(46_454_287u32); assert!(valid.is_valid()); assert!(!invalid.is_valid()); } #[test] //#[ignore] fn you_can_validate_from_a_u64() { let valid = Luhn::from(8273_1232_7352_0562u64); let invalid = Luhn::from(8273_1232_7352_0569u64); assert!(valid.is_valid()); assert!(!invalid.is_valid()); } #[test] //#[ignore] fn you_can_validate_from_a_usize() { let valid = Luhn::from(8273_1232_7352_0562usize); let invalid = Luhn::from(8273_1232_7352_0569usize); assert!(valid.is_valid()); assert!(!invalid.is_valid()); } #[test] //#[ignore] fn single_digit_string_is_invalid() { assert!(!Luhn::from("1").is_valid()); } #[test] //#[ignore] fn single_zero_string_is_invalid() { assert!(!Luhn::from("0").is_valid()); } #[test] //#[ignore] fn valid_canadian_sin_is_valid() { assert!(Luhn::from("046 454 286").is_valid()); } #[test] //#[ignore] fn invalid_canadian_sin_is_invalid() { assert!(!Luhn::from("046 454 287").is_valid()); } #[test] //#[ignore] fn invalid_credit_card_is_invalid() { assert!(!Luhn::from("8273 1232 7352 0569").is_valid()); } #[test] //#[ignore] fn strings_that_contain_non_digits_are_invalid() { assert!(!Luhn::from("046a 454 286").is_valid()); } #}
4. 答案
# #![allow(unused_variables)] #fn main() { pub struct Luhn { digits: Vec<char>, } impl Luhn { pub fn is_valid(&self) -> bool { if self.digits.iter().any(|c| c.is_alphabetic()) || self.digits.iter().count() == 1 { return false; } self.digits .iter() .filter_map(|c| c.to_digit(10)) .rev() .enumerate() .map(|(index, digit)| if index % 2 == 0 { digit } else { digit * 2 }) .map(|digit| if digit > 9 { digit - 9 } else { digit }) .sum::<u32>() % 10 == 0 } } impl From<String> for Luhn { fn from(s: String) -> Self { Luhn { digits: s.chars().collect(), } } } impl<'a> From<&'a str> for Luhn { fn from(s: &'a str) -> Self { Luhn::from(String::from(s)) } } impl From<u8> for Luhn { fn from(s: u8) -> Self { Luhn::from(s.to_string()) } } impl From<u16> for Luhn { fn from(s: u16) -> Self { Luhn::from(s.to_string()) } } impl From<u32> for Luhn { fn from(s: u32) -> Self { Luhn::from(s.to_string()) } } impl From<u64> for Luhn { fn from(s: u64) -> Self { Luhn::from(s.to_string()) } } impl From<usize> for Luhn { fn from(s: usize) -> Self { Luhn::from(s.to_string()) } } #}