Решение на Дигитален корен от Георги Петков

Обратно към всички решения

Към профила на Георги Петков

Резултати

  • 20 точки от тестове
  • 0 бонус точки
  • 20 точки общо
  • 6 успешни тест(а)
  • 0 неуспешни тест(а)

Код

fn ch_to_int(ch: char) -> u32 {
ch.to_digit(16).unwrap_or(0)
}

Тази функция е малко странна. Какво става ако подадем символа 0? Ще получим числото 0, също както бихме получили това число в случай на невалиден вход. Няма разлика между грешен вход и валидния вход 0.

Причината да работи е защото правиш валидация преди това. Ако случайно забравиш да валидираш някъде, този код ще е silently wrong, which is the worst kind of wrong :). Доста по-добре за целите на дебъгването е да викнеш unwrap() тук, за да спреш цялата програма, отколкото да връщаш грешен резултат, но само понякога.

(Още по-добре е да използваш това, което функцията ти връща -- вместо да валидираш първо, и после да process-ваш, можеш директно да сложиш една if/match-клауза докато process-ваш и да върнеш None в случай на грешка.)

fn digit_sum_from_str(s: &String) -> u32 {
let mut sum: u32 = 0;
for ch in s.chars() {
sum += ch_to_int(ch);
}
sum
}
fn digit_sum(num: u32, radix: u32) -> u32 {
let mut sum = 0;
let mut n = num;
while n != 0 {
sum += n%radix;
n /= radix;
}
sum
}
fn digital_root(input: &String, radix: u32) -> u32 {
let mut sum = digit_sum_from_str(&input);
while sum >= radix {
sum = digit_sum(sum, radix);
}
sum
}
/// Десетична бройна система: 0-9
pub fn decimal(input: &str) -> Option<u32> {
let s = String::from(input);
let dec_numbers_only = s.chars().all(char::is_numeric);
if !dec_numbers_only {
None
} else {
let num = digital_root(&s, 10);
Some(num)
}
}
fn a_to_f(ch: char) -> bool {
(ch>='a' && ch<='f')
}

Не е много добро име за функцията -- a_to_f ми изглежда като функция, която конвертира от нещо до нещо, заради to-то. По-удачно щеше да бъде да я наречеш valid_hex или нещо такова и да вкараш логиката char::is_numeric(x) тук.

Макар че можеше и да използваш char::is_digit(16) директно. Или още по-добре, char::to_digit(16), което ако ти върне в какъвто и да е момент None, да върнеш и ти None от функцията hex.

Иначе, ако ти изглежда по-смислено да имаш функция, която проверява само тази логика, по-добро име би било може би between_a_and_f и съответно between_0_and_7.

/// Шестнадесетична бройна система: 0-9, последвано от a-f
pub fn hex(input: &str) -> Option<u32> {
let s = String::from(input);
let hex_numbers_only = s.chars().all(|x| {char::is_numeric(x) || a_to_f(x)});
if !hex_numbers_only {
None
} else {
let num = digital_root(&s, 16);
Some(num)
}
}
fn zero_to_seven(ch: char) -> bool {
(ch>='0' && ch<='7')
}
/// Осмична бройна система: 0-7
pub fn octal(input: &str) -> Option<u32> {
let s = String::from(input);
let octal_numbers_only = s.chars().all(zero_to_seven);
if !octal_numbers_only {
None
} else {
let num = digital_root(&s, 8);
Some(num)
}
}
/// Двоична бройна система: 0-1
pub fn binary(input: &str) -> Option<u32> {
let s = String::from(input);
let bin_numbers_only = s.chars().all(|x| {x=='0' || x=='1'});
if !bin_numbers_only {
None
} else {
let num = digital_root(&s, 2);
Some(num)
}
}

Лог от изпълнението

Compiling solution v0.1.0 (/tmp/d20200111-2173579-17clggr/solution)
    Finished test [unoptimized + debuginfo] target(s) in 1.79s
     Running target/debug/deps/solution-a73e64ec87929bd0

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running target/debug/deps/solution_test-38971695424b36d5

running 6 tests
test solution_test::test_binary ... ok
test solution_test::test_decimal_basic ... ok
test solution_test::test_hex_basic ... ok
test solution_test::test_invalid ... ok
test solution_test::test_octal_basic ... ok
test solution_test::test_zeroes ... ok

test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

   Doc-tests solution

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

История (1 версия и 3 коментара)

Георги качи първо решение на 05.11.2019 13:27 (преди почти 6 години)