[英]Why unable to parse a string | Rust
我正在制作十進制到二進制的轉換程序。 為什么我無法將字符串解析為數字? 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。
編寫的代碼存在很多問題。 好消息是,您可以通過聽編譯器警告來解決大多數問題!
--> 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
運行。 如果尚未安裝rustup install component 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)
2 ^ (i as u32)
替換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。我們的答案終於是正確的! 在更多輸入上對其進行測試,並嘗試找到一些邊緣情況。 還有更多的錯誤可以找到。 對代碼滿意后,取出調試語句。
我通常會嘗試修復代碼,但這似乎有些令人費解。
這是一個更簡單的解決方案:
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)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.