(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(())
}

相关推荐
程序员爱钓鱼12 小时前
Rust if let 与 while let 详解:简化模式匹配
前端·后端·rust
第一程序员1 天前
Rust trait 入门:把 AI 客户端抽象成可替换接口
python·rust·github
分布式存储与RustFS1 天前
RustFS Beta.10 性能解读:PUT 全面反超 MinIO,Rust 重写对象存储成了?
开发语言·后端·rust
l1t1 天前
测试用rust重写的postgresql: pgrust
开发语言·postgresql·rust
@atweiwei1 天前
Langchainrust:中LLM-as-a-Judge,用 Rust 实现一套 LLM 评估系统
开发语言·后端·ai·rust·llm·rag
程序员爱钓鱼2 天前
Rust match 模式匹配详解:比 if 更强大的条件分支
后端·rust
爱吃牛肉的大老虎2 天前
rust基础之环境搭建
java·开发语言·rust
openKylin2 天前
与全球技术演进同频,openKylin 3.0从C迈向Rust
c语言·开发语言·rust·开源·开放原子·openkylin
Source.Liu2 天前
【A11】Duration —— 精确时长结构体实现
rust·time
右耳朵猫AI_2 天前
用 Rust 重写 Bun
rust·bun