Rustlings Errors3.rs 从字符串转换错误 - 未为 `std::string::String` 实现特征

Rustlings Errors3.rs Convert From String Error - Trait Not Implemented for `std::string::String`

我正在学习 Rustlings 课程 Errors3.rs:

// This is a program that is trying to use a completed version of the
// `total_cost` function from the previous exercise. It's not working though!
// Why not? What should we do to fix it?

use std::num::ParseIntError;

fn main() {
    let mut tokens = 100;
    let pretend_user_input = "8";

    let cost = total_cost(pretend_user_input)?;

    if cost > tokens {
        println!("You can't afford that many!");
    } else {
        tokens -= cost;
        println!("You now have {} tokens.", tokens);
    }
}

pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
    let processing_fee = 1;
    let cost_per_item = 5;
    let qty = item_quantity.parse::<i32>()?;

    Ok(qty * cost_per_item + processing_fee)
}

这是我当前的代码:

use std::num::ParseIntError;

fn main() -> Result<String, String>  {
    let mut tokens = 100;
    let pretend_user_input = "8";

    let cost = total_cost(pretend_user_input)?;

    if cost > tokens {
        //println!("You can't afford that many!");
        Ok(format!("You can't afford that many!"))
    } else {
        tokens -= cost;
        //println!("You now have {} tokens.", tokens);
        Err(format!("You now have {} tokens.", tokens).to_string())
    }

}

pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
    let processing_fee = 1;
    let cost_per_item = 5;
    let qty = item_quantity.parse::<i32>()?;

    Ok(qty * cost_per_item + processing_fee)
}

我不知道如何纠正第一个错误:

error[E0277]: `?` couldn't convert the error to `std::string::String`
 --> src/main.rs:7:46
  |
7 |     let cost = total_cost(pretend_user_input)?;
  |                                              ^ the trait `std::convert::From<std::num::ParseIntError>` is not implemented for `std::string::String`
  |
  = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
  = help: the following implementations were found:
            <std::string::String as std::convert::From<&std::string::String>>
            <std::string::String as std::convert::From<&str>>
            <std::string::String as std::convert::From<std::borrow::Cow<'a, str>>>
            <std::string::String as std::convert::From<std::boxed::Box<str>>>
  = note: required by `std::convert::From::from`

error[E0277]: `main` has invalid return type `std::result::Result<std::string::String, std::string::String>`
 --> src/main.rs:3:14
  |
3 | fn main() -> Result<String, String>  {
  |              ^^^^^^^^^^^^^^^^^^^^^^ `main` can only return types that implement `std::process::Termination`
  |
  = help: consider using `()`, or a `Result`

根据建议,关于 From,我尝试将 Ok(format!("You can't afford that many!")) 更改为 Ok(String::from("You can't afford that many!"))。但它会导致几乎相同的错误消息。

我已经尝试查看 std::convert::From 的 Rust 文档。这给了我尝试的想法:


let slug: &'static str = "You can't afford that many!";
if cost > tokens {
    //println!("You can't afford that many!");
    Ok(std::convert::From(slug))
} else {
    tokens -= cost;
    //println!("You now have {} tokens.", tokens);
    Err(format!("You now have {} tokens.", tokens).to_string())
}

导致错误:

error[E0423]: expected function, tuple struct or tuple variant, found trait `std::convert::From`
  --> src/main.rs:12:12
   |
12 |         Ok(std::convert::From(slug))
   |            ^^^^^^^^^^^^^^^^^^ not a function, tuple struct or tuple variant

你试图改变原始程序的行为,程序必须打印一些不是 return 主字符串的东西(实际上你不能 return 主字符串,你必须 return 实现 Termination) 的东西。

解决方案与您所做的接近,main() 也必须 return 一个错误,有两种方法,使用真实类型或使用动态特征。你的case很简单所以real type是最简单的:

use std::num::ParseIntError;

fn main() -> Result<(), ParseIntError> {
    let mut tokens = 100;
    let pretend_user_input = "8";

    let cost = total_cost(pretend_user_input)?;

    if cost > tokens {
        println!("You can't afford that many!");
    } else {
        tokens -= cost;
        println!("You now have {} tokens.", tokens);
    }

    // we just return ok with nothing in it, this mean program terminated without error
    Ok(())
}

pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
    let processing_fee = 1;
    let cost_per_item = 5;
    let qty = item_quantity.parse::<i32>()?;

    Ok(qty * cost_per_item + processing_fee)
}

但你也可以使用动态特征,它更先进但不是特别好:

use std::num::ParseIntError;
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    let mut tokens = 100;
    let pretend_user_input = "8";

    let cost = total_cost(pretend_user_input)?;

    if cost > tokens {
        println!("You can't afford that many!");
    } else {
        tokens -= cost;
        println!("You now have {} tokens.", tokens);
    }

    Ok(())
}

pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
    let processing_fee = 1;
    let cost_per_item = 5;
    let qty = item_quantity.parse::<i32>()?;

    Ok(qty * cost_per_item + processing_fee)
}

在 Rust 中有很多处理错误的方法。您可以在 this blog post.

上学到很多东西

提示说要使用不同的方法来避免“?”操作员。 这是我的解决方案。

// errors3.rs
// This is a program that is trying to use a completed version of the
// `total_cost` function from the previous exercise. It's not working though!
// Why not? What should we do to fix it?
// Execute `rustlings hint errors3` for hints!


// I AM NOT DONE

use std::num::ParseIntError;

fn main() -> Result<(),ParseIntError>{
    let mut tokens = 100;
    let pretend_user_input = "8";
    let cost = total_cost(pretend_user_input);
    match cost {
        Ok(x) if x > tokens => 
            println!("You can't afford that many!"),
        Ok(x) => { 
            tokens -= x;
            println!("You now have {} tokens.", tokens);
        },
        Err(e) => (), 
    }
    Ok(())
}

pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
    let processing_fee = 1;
    let cost_per_item = 5;
    let qty = item_quantity.parse::<i32>()?;

    Ok(qty * cost_per_item + processing_fee)    
}