解答

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;

7. for c in cc_number.chars().rev() {
8. if let Some(digit) = c.to_digit(10) {
9. if double {
10. let double_digit = digit * 2;
11. sum +=
12. if double_digit > 9 { double_digit - 9 } else { double_digit };
13. } else {
14. sum += digit;
15. }
16. double = !double;
17. } else {
18. continue;
19. }
20. }

22. sum % 10 == 0
23. }

25. // This is the solution and passes all of the tests below.
26. pub fn luhn(cc_number: &str) -> bool {
27. let mut sum = 0;
28. let mut double = false;
29. let mut digits = 0;

31. for c in cc_number.chars().rev() {
32. if let Some(digit) = c.to_digit(10) {
33. digits += 1;
34. if double {
35. let double_digit = digit * 2;
36. sum +=
37. if double_digit > 9 { double_digit - 9 } else { double_digit };
38. } else {
39. sum += digit;
40. }
41. double = !double;
42. } else if c.is_whitespace() {
43. continue;
44. } else {
45. return false;
46. }
47. }

49. digits >= 2 && sum % 10 == 0
50. }

52. fn main() {
53. let cc_number = "1234 5678 1234 5670";
54. println!(
55. "Is {cc_number} a valid credit card number? {}",
56. if luhn(cc_number) { "yes" } else { "no" }
57. );
58. }

60. #[cfg(test)]
61. mod test {
62. use super::*;

64. #[test]
65. fn test_valid_cc_number() {
66. assert!(luhn("4263 9826 4026 9299"));
67. assert!(luhn("4539 3195 0343 6467"));
68. assert!(luhn("7992 7398 713"));
69. }

71. #[test]
72. fn test_invalid_cc_number() {
73. assert!(!luhn("4223 9826 4026 9299"));
74. assert!(!luhn("4539 3195 0343 6476"));
75. assert!(!luhn("8273 1232 7352 0569"));
76. }

78. #[test]
79. fn test_non_digit_cc_number() {
80. assert!(!luhn("foo"));
81. assert!(!luhn("foo 0 0"));
82. }

84. #[test]
85. fn test_empty_cc_number() {
86. assert!(!luhn(""));
87. assert!(!luhn(" "));
88. assert!(!luhn("  "));
89. assert!(!luhn("    "));
90. }

92. #[test]
93. fn test_single_digit_cc_number() {
94. assert!(!luhn("0"));
95. }

97. #[test]
98. fn test_two_digit_cc_number() {
99. assert!(luhn(" 0 0 "));
100. }
101. }