解答

  1. // This is the buggy version that appears in the problem.
  2. #[cfg(never)]
  3. pub fn luhn(cc_number: &str) -> bool {
  4. let mut sum = 0;
  5. let mut double = false;
  6. for c in cc_number.chars().rev() {
  7. if let Some(digit) = c.to_digit(10) {
  8. if double {
  9. let double_digit = digit * 2;
  10. sum +=
  11. if double_digit > 9 { double_digit - 9 } else { double_digit };
  12. } else {
  13. sum += digit;
  14. }
  15. double = !double;
  16. } else {
  17. continue;
  18. }
  19. }
  20. sum % 10 == 0
  21. }
  22. // This is the solution and passes all of the tests below.
  23. pub fn luhn(cc_number: &str) -> bool {
  24. let mut sum = 0;
  25. let mut double = false;
  26. let mut digits = 0;
  27. for c in cc_number.chars().rev() {
  28. if let Some(digit) = c.to_digit(10) {
  29. digits += 1;
  30. if double {
  31. let double_digit = digit * 2;
  32. sum +=
  33. if double_digit > 9 { double_digit - 9 } else { double_digit };
  34. } else {
  35. sum += digit;
  36. }
  37. double = !double;
  38. } else if c.is_whitespace() {
  39. continue;
  40. } else {
  41. return false;
  42. }
  43. }
  44. digits >= 2 && sum % 10 == 0
  45. }
  46. fn main() {
  47. let cc_number = "1234 5678 1234 5670";
  48. println!(
  49. "Is {cc_number} a valid credit card number? {}",
  50. if luhn(cc_number) { "yes" } else { "no" }
  51. );
  52. }
  53. #[cfg(test)]
  54. mod test {
  55. use super::*;
  56. #[test]
  57. fn test_valid_cc_number() {
  58. assert!(luhn("4263 9826 4026 9299"));
  59. assert!(luhn("4539 3195 0343 6467"));
  60. assert!(luhn("7992 7398 713"));
  61. }
  62. #[test]
  63. fn test_invalid_cc_number() {
  64. assert!(!luhn("4223 9826 4026 9299"));
  65. assert!(!luhn("4539 3195 0343 6476"));
  66. assert!(!luhn("8273 1232 7352 0569"));
  67. }
  68. #[test]
  69. fn test_non_digit_cc_number() {
  70. assert!(!luhn("foo"));
  71. assert!(!luhn("foo 0 0"));
  72. }
  73. #[test]
  74. fn test_empty_cc_number() {
  75. assert!(!luhn(""));
  76. assert!(!luhn(" "));
  77. assert!(!luhn(" "));
  78. assert!(!luhn(" "));
  79. }
  80. #[test]
  81. fn test_single_digit_cc_number() {
  82. assert!(!luhn("0"));
  83. }
  84. #[test]
  85. fn test_two_digit_cc_number() {
  86. assert!(luhn(" 0 0 "));
  87. }
  88. }