簡體   English   中英

為什么無法解析字符串 銹

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM