(done) 速通 rustlings(20) 错误处理1 --- 不涉及Traits

RUST 内置 Result, Err, Ok

如下是示例代码:

rust 复制代码
// This function refuses to generate text to be printed on a nametag if
// you pass it an empty string. Instead of returning `None`, it should give
// an error message explaining what went wrong. The caller can then inspect
// the `Result` to see either the generated text or the explanation.
fn generate_nametag_text(name: String) -> Result<String, String> {
    if name.is_empty() {
        // Empty names aren't allowed
        Err("Empty names aren't allowed".to_string())
    } else {
        Ok(format!("Hi! My name is {name}"))
    }
}

fn main() {
    // You can optionally experiment here.
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn generates_nametag_text_for_a_nonempty_name() {
        assert_eq!(
            generate_nametag_text("Beyoncé".to_string()).as_deref(),
            Ok("Hi! My name is Beyoncé"),
        );
    }

    #[test]
    fn explains_why_generating_nametag_text_fails() {
        assert_eq!(
            generate_nametag_text(String::new())
                .as_ref()
                .map_err(|e| e.as_str()),
            Err("Empty names aren't allowed"),
        );
    }
}

? 操作符

RUST,一个函数返回一个 Result 后,并赋值给一个变量时,

rust 复制代码
 let qty = item_quantity.parse::<i32>()?;

中的 "?" 表示:如果 parse 出现错误,提前 return Err(e) 给 caller。

若 parse 未出现错误,则 qty 获取 parse 后的值。

等效于下面的写法:

rust 复制代码
    // Equivalent to this verbose version:
    let qty = match item_quantity.parse::<i32>() {
        Ok(v) => v,
        Err(e) => return Err(e),
    };

完整代码示例如下:

rust 复制代码
// Say we're writing a game where you can buy items with tokens. All items cost
// 5 tokens, and whenever you purchase items there is a processing fee of 1
// token. A player of the game will type in how many items they want to buy, and
// the `total_cost` function will calculate the total cost of the items. Since
// the player typed in the quantity, we get it as a string. They might have
// typed anything, not just numbers!
//
// Right now, this function isn't handling the error case at all. What we want
// to do is: If we call the `total_cost` function on a string that is not a
// number, that function will return a `ParseIntError`. In that case, we want to
// immediately return that error from our function and not try to multiply and
// add.
//
// There are at least two ways to implement this that are both correct. But one
// is a lot shorter!

use std::num::ParseIntError;

#[allow(unused_variables)]
fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
    let processing_fee = 1;
    let cost_per_item = 5;

    // Added `?` to propagate the error.
    let qty = item_quantity.parse::<i32>()?;
    //                                    ^ added

    // Equivalent to this verbose version:
    let qty = match item_quantity.parse::<i32>() {
        Ok(v) => v,
        Err(e) => return Err(e),
    };

    let qty = item_quantity.parse::<i32>();

    Ok(qty * cost_per_item + processing_fee)
}

fn main() {
    // You can optionally experiment here.
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::num::IntErrorKind;

    #[test]
    fn item_quantity_is_a_valid_number() {
        assert_eq!(total_cost("34"), Ok(171));
    }

    #[test]
    fn item_quantity_is_an_invalid_number() {
        assert_eq!(
            total_cost("beep boop").unwrap_err().kind(),
            &IntErrorKind::InvalidDigit,
        );
    }
}

易错点1:caller 没有加返回值

RUST 中,如果你调用了一个含有错误处理的函数,且没有处理错误情况而是选择抛出,那么通常 caller 的函数返回值需要加上 Result<..., ...>,如下:

rust 复制代码
// 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;

// Don't change this function.
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)
}

fn main() -> Result<(), ParseIntError> {
    //    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ added
    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.");
    }

    // Added this line to return the `Ok` variant of the expected `Result`.
    Ok(())
}

相关推荐
shimly1234561 小时前
(done) 速通 rustlings(19) Option
rust
@atweiwei1 小时前
rust所有权机制详解
开发语言·数据结构·后端·rust·内存·所有权
shimly1234562 小时前
(done) 速通 rustlings(24) 错误处理2 --- 涉及Traits
rust
shimly1234562 小时前
(done) 速通 rustlings(23) 特性 Traits
rust
shimly1234563 小时前
(done) 速通 rustlings(17) 哈希表
rust
shimly1234564 小时前
(done) 速通 rustlings(15) 字符串
rust
shimly1234565 小时前
(done) 速通 rustlings(22) 泛型
rust
yezipi耶不耶5 小时前
我在 RTMate 里使用的高并发连接管理利器: DashMap
websocket·rust
初恋叫萱萱11 小时前
深入解析 Rust + LLM 开发:手把手教你写一个 AI 运维助手
运维·人工智能·rust