我正在制作从十进制到二进制的转换程序。为什么我无法将字符串解析为数字? binary_vec[i]
是character
。我使用to_string()
方法将其转换为字符串,因为parse()
不适用于字符,但仍然给我一个错误。
use std::io;
fn main() {
let mut binary = String::new();
println!("Enter a decimal: ");
io::stdin().read_line(&mut binary)
.ok()
.expect("Couldn't read line");
println!("{}",to_decimal(binary));
}
fn to_decimal(mut binary_str:String) -> String {
let mut binary_no: u32 = binary_str.trim().parse().expect("invalid input");
if binary_no == 0 {
format!("{}",binary_no)
}
else {
let mut bits = String::new();
let mut binary_vec: Vec<char> = binary_str.chars().collect();
let mut result = 0;
let mut i = 0;
while i <=binary_str.len()-2{
let mut result = result + (binary_vec[i].to_string().parse::<u32>().unwrap() * 2^(i as u32));
i = i +1;
}
format!("{}",result)
}
}
结果:
Compiling sixteen v0.1.0 (C:\Users\Muhammad.3992348\Desktop\rust\hackathon\sixteen)
warning: unused variable: `bits`
--> 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
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`
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
warning: variable does not need to be mutable
--> src\main.rs:14:9
|
14 | let mut binary_no: u32 = binary_str.trim().parse().expect("invalid input");
| ----^^^^^^^^^
| |
| help: remove this `mut`
warning: variable does not need to be mutable
--> src\main.rs:19:13
|
19 | let mut bits = String::new();
| ----^^^^
| |
| help: remove this `mut`
warning: variable does not need to be mutable
--> src\main.rs:20:13
|
20 | let mut binary_vec: Vec<char> = binary_str.chars().collect();
| ----^^^^^^^^^^
| |
| help: remove this `mut`
warning: variable does not need to be mutable
--> src\main.rs:21:13
|
21 | let mut result = 0;
| ----^^^^^^
| |
| help: remove this `mut`
warning: variable does not need to be mutable
--> src\main.rs:24:17
|
24 | let mut result = result + (binary_vec[i].to_string().parse::<u32>().unwrap() * 2^(i as u32));
| ----^^^^^^
| |
| help: remove this `mut`
Finished dev [unoptimized + debuginfo] target(s) in 1.04s
Running `target\debug\sixteen.exe`
Enter a decimal:
100
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ParseIntError { kind: InvalidDigit }', src\libcore\result.rs:997:5
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
error: process didn't exit successfully: `target\debug\sixteen.exe` (exit code: 101)
编辑: 我已经输入了100,我希望输出为4。
答案 0 :(得分:8)
编写的代码有很多问题。好消息是,您可以通过听编译器警告来解决大多数问题!
--> 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
哦,哦。 Clippy告诉我们优先级规则表明*
在^
之前被求值。这不是我们对乘法和指数的期望。事实证明^
不是指数运算符。相反,它是按位异或。如果需要数字的幂,可以使用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。我们的答案终于正确了!在更多输入上对其进行测试,并尝试找到一些边缘情况。还有更多的错误可以找到。对代码满意后,取出调试语句。
答案 1 :(得分:0)
我通常会尝试修复代码,但这似乎有点令人费解。
这是一个更简单的解决方案:
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");
match to_decimal(binary) {
Some(num) => println!("{}", num),
None => println!("Not a binary!")
}
}
fn to_decimal(binary_str:String) -> Option<i64> {
let binary_str = binary_str.trim();
let mut out_num = 0;
for c in binary_str.chars() {
match c {
'0' => out_num = out_num * 2,
'1' => out_num = out_num * 2 + 1,
_ => return None
}
}
Some(out_num)
}