Есть много проблем с кодом, как написано. Хорошей новостью является то, что большинство проблем можно устранить, прослушав предупреждения компилятора!
--> src/main.rs:19:17
|
19 | let mut bits = String::new();
| ^^^^ help: consider prefixing with an underscore: `_bits`
|
= note: #[warn(unused_variables)] on by default
Это говорит о том, что переменная bits
не используется после этого объявления. Если вы намереваетесь использовать его позже, вы можете просто закомментировать его.
warning: unused variable: `result`
--> src/main.rs:24:21
|
24 | let mut result = result + (binary_vec[i].to_string().parse::<u32>().unwrap() * 2^(i as u32));
| ^^^^^^ help: consider prefixing with an underscore: `_result`
|
= note: #[warn(unused_variables)] on by default
Это большой. Это говорит нам о том, что переменная result
не используется. Но ждать! мы используем это прямо здесь! Нету! На самом деле, используя let mut
здесь, мы создаем новую переменную и скрываем старую. Вместо этого вам нужно перезаписать старое значение. Просто измените let mut result = ...
на result = ...
.
Теперь, если мы снова запустим программу и введем 100
, мы получим вывод 5
. Это все еще кажется неправильным, но у нас все еще есть несколько предупреждений, которые нужно исправить, поэтому давайте вернемся к этому.
warning: variable does not need to be mutable
--> src/main.rs:13:15
|
13 | fn to_decimal(mut binary_str:String) -> String {
| ----^^^^^^^^^^
| |
| help: remove this `mut`
|
= note: #[warn(unused_mut)] on by default
Если мы не собираемся изменять входную строку, мы не должны делать ее изменяемой. Просто удалите mut
. То же самое для двух других предупреждений (строки 14 и 20).
Хорошо! Теперь мы можем запустить программу без каких-либо предупреждений. Тем не менее, есть несколько более сложных линтов, которые мы можем использовать, используя cargo clippy
. Если у вас еще не установлен clippy, вы можете установить его с помощью rustup install component clippy
.
Теперь у нас есть еще несколько предупреждений, о которых нужно позаботиться.
warning: operator precedence can trip the unwary
--> src/main.rs:24:32
|
24 | result = result + (binary_vec[i].to_string().parse::<u32>().unwrap() * 2^(i as u32));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `(binary_vec[i].to_string().parse::<u32>().unwrap() * 2) ^ (i as u32)`
|
= note: #[warn(clippy::precedence)] on by default
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#precedence
Э-э-э Клиппи говорит нам, что правила предшествования указывают, что *
оценивается до ^
. Это не то, что мы ожидаем от умножения и показателей. Оказывается, что ^
является , а не оператором степени. Вместо этого это побитовый xor. Если мы хотим получить степень числа, мы можем использовать метод pow
, поэтому замените 2 ^ (i as u32)
на 2.pow(i as u32)
. Это приведет к ошибке компилятора с сообщением error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}`
. Хорошо. Мы можем сделать числовой тип однозначным, используя суффикс. Измените его на 2_u32.pow(i as u32)
.
Мы можем исправить три других предупреждения, которые Clippy дает нам, просто воспользовавшись предложением. После этого Clippy выдает еще одно предупреждение, которое также исправляется только предложением.
Прежде чем мы продолжим, давайте сделаем наш код немного красивее, запустив cargo fmt
. Наконец, код выглядит так:
use std::io;
fn main() {
let mut binary = String::new();
println!("Enter a decimal: ");
io::stdin()
.read_line(&mut binary)
.expect("Couldn't read line");
println!("{}", to_decimal(binary));
}
fn to_decimal(binary_str: String) -> String {
let binary_no: u32 = binary_str.trim().parse().expect("invalid input");
if binary_no == 0 {
format!("{}", binary_no)
} else {
//let mut bits = String::new();
let binary_vec: Vec<char> = binary_str.chars().collect();
let mut result = 0;
let mut i = 0;
while i <= binary_str.len() - 2 {
result += binary_vec[i].to_string().parse::<u32>().unwrap() * 2_u32.pow(i as u32);
i += 1;
}
format!("{}", result)
}
}
Мы исправили две ошибки и очистили код только с помощью предупреждений компилятора и базовых инструментов! Довольно хорошо, а? Но теперь, если мы введем 100
, мы получим 1
. Это не правильно. Давайте добавим несколько операторов отладки, чтобы увидеть, можем ли мы увидеть, что происходит.
result += dbg!(binary_vec[i].to_string().parse::<u32>().unwrap()) * dbg!(2_u32.pow(i as u32));
Если мы запустим его сейчас, вот что мы получим.
Enter a decimal:
100
[src/main.rs:22] binary_vec[i].to_string().parse::<u32>().unwrap() = 1
[src/main.rs:22] 2u32.pow(i as u32) = 1
[src/main.rs:22] binary_vec[i].to_string().parse::<u32>().unwrap() = 0
[src/main.rs:22] 2u32.pow(i as u32) = 2
[src/main.rs:22] binary_vec[i].to_string().parse::<u32>().unwrap() = 0
[src/main.rs:22] 2u32.pow(i as u32) = 4
1
Мы видим, что он правильно разбирает цифры: binary_vec[i].to_string().parse::<u32>().unwrap()
- это 1
, затем 0
, затем 0
. Сила 2 тоже выглядит хорошо. Проблема здесь в том, что это задом наперед! Мы хотим, чтобы левая цифра умножалась на наибольшую степень 2. Позвольте мне заметить, что это часть кода, где вы наименее идиоматичны. Гораздо лучше использовать, по крайней мере, цикл for
для такого рода вещей. Итераторы были бы еще лучше, если бы вы могли управлять ими.
В любом случае, мы можем изменить порядок, заставив наши силы перейти от binary_str.len() - 2
до 0
, а не наоборот. Таким образом, мы можем изменить код на
while i <= binary_str.len() - 2 {
result += dbg!(binary_vec[i].to_string().parse::<u32>().unwrap()) * dbg!(2_u32.pow((binary_str.len() - 2 - i) as u32));
i += 1;
}
Получаем
Enter a decimal:
100
[src/main.rs:22] binary_vec[i].to_string().parse::<u32>().unwrap() = 1
[src/main.rs:22] 2u32.pow((binary_str.len() - 2 - i) as u32) = 4
[src/main.rs:22] binary_vec[i].to_string().parse::<u32>().unwrap() = 0
[src/main.rs:22] 2u32.pow((binary_str.len() - 2 - i) as u32) = 2
[src/main.rs:22] binary_vec[i].to_string().parse::<u32>().unwrap() = 0
[src/main.rs:22] 2u32.pow((binary_str.len() - 2 - i) as u32) = 1
4
так что мы видим, что полномочия правильно поменялись местами с 4 до 1. И наш ответ, наконец, правильный! Протестируйте его еще на нескольких входах и попытайтесь найти некоторые крайние случаи. Есть еще несколько ошибок, чтобы найти. Как только вы довольны своим кодом, выньте операторы отладки.