Luhn Trait
1. Readme
鲁恩 trait
Luhn: 使用自定义 trait
在做这个练习之前,你应该做原始的 luhn 练习和进阶练习,”luhn:使用 From trait”.
要获得原始的 Luhn 练习,运行
exercism download --exercise=luhn --track=rust
要获得”Lunn:使用 From trait”的练习,运行
exercism download --exercise=luhn-from --track=rust
在原始的 luhn 练习中,您只验证字符串,但 luhn 算法也可以应用于整数。
在”Lurn:使用 From trait”中,你实现了一个 From trait,还需要你创建一个 luhn 结构。
要是不创建一个结构来执行验证呢,如果要您自己验证了原语本身(即,String,u8 等)呢?
在本练习中,您将创建并实现自定义trait,来执行验证.
注:它是实现原语的 trait,不是 Rust 的习惯。 在这个练习中,我们展示了一些你可以做的东西,而不是你应该做的东西。如果你发现自己在原语上实现了 trait,也许你有一个Primitive Obsession例子。
资源
基于原始 luhn 练习,延续 Rust 轨迹
2. 开始你的表演
pub trait Luhn { fn valid_luhn(&self) -> bool; } /// Here is the example of how to implement custom Luhn trait /// 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> Luhn for &'a str { fn valid_luhn(&self) -> bool { unimplemented!("Determine if '{}' is a valid credit card number.", self); } }
3. 测试代码查看
# #![allow(unused_variables)] #fn main() { #[test] fn you_can_validate_from_a_str() { assert!("046 454 286".valid_luhn()); assert!(!"046 454 287".valid_luhn()); } #[test] //#[ignore] fn you_can_validate_from_a_string() { assert!(String::from("046 454 286").valid_luhn()); assert!(!String::from("046 454 287").valid_luhn()); } #[test] //#[ignore] fn you_can_validate_from_a_u8() { assert!(240u8.valid_luhn()); assert!(!241u8.valid_luhn()); } #[test] //#[ignore] fn you_can_validate_from_a_u16() { let valid = 64_436u16; let invalid = 64_437u16; assert!(valid.valid_luhn()); assert!(!invalid.valid_luhn()); } #[test] //#[ignore] fn you_can_validate_from_a_u32() { let valid = 46_454_286u32; let invalid = 46_454_287u32; assert!(valid.valid_luhn()); assert!(!invalid.valid_luhn()); } #[test] //#[ignore] fn you_can_validate_from_a_u64() { let valid = 8273_1232_7352_0562u64; let invalid = 8273_1232_7352_0569u64; assert!(valid.valid_luhn()); assert!(!invalid.valid_luhn()); } #[test] //#[ignore] fn you_can_validate_from_a_usize() { let valid = 8273_1232_7352_0562usize; let invalid = 8273_1232_7352_0569usize; assert!(valid.valid_luhn()); assert!(!invalid.valid_luhn()); } #}
4. 答案
# #![allow(unused_variables)] #fn main() { pub trait Luhn { fn valid_luhn(&self) -> bool; } impl Luhn for String { fn valid_luhn(&self) -> bool { if self.chars().any(|c| c.is_alphabetic()) || self.chars().count() == 1 { return false; } self.chars() .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<'a> Luhn for &'a str { fn valid_luhn(&self) -> bool { String::from(*self).valid_luhn() } } impl Luhn for u8 { fn valid_luhn(&self) -> bool { self.to_string().valid_luhn() } } impl Luhn for u16 { fn valid_luhn(&self) -> bool { self.to_string().valid_luhn() } } impl Luhn for u32 { fn valid_luhn(&self) -> bool { self.to_string().valid_luhn() } } impl Luhn for u64 { fn valid_luhn(&self) -> bool { self.to_string().valid_luhn() } } impl Luhn for usize { fn valid_luhn(&self) -> bool { self.to_string().valid_luhn() } } #}