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

相关推荐
Albart57510 小时前
【玩转 AtomCode】替代Claude Code!开源多模型免费AI编码Agent深度实测教程
人工智能·rust·开源·atomcode·多模型ai
特立独行的猫A10 小时前
Rust+Tauri 2实现个人聚藏APP:一个 “注定上不了“ 的个人收藏夹
rust
jeffwang11 小时前
我把同一个压测做错了三次,第四次才发现真正的瓶颈
分布式·性能优化·rust
程序员爱钓鱼12 小时前
Rust 生命周期详解:生命周期标注、约束与真实项目应用
后端·面试·rust
MoonBit月兔12 小时前
MoonBit 受邀亮相 SPLASH/ISSTA 2026,与 Java、Rust、Eiffel、D 语言核心贡献者同场交流
开发语言·后端·rust
今天AI了吗12 小时前
Python vs Rust AI 服务基准测试全景:FastAPI、Axum、Actix-Web 的延迟与吞吐
人工智能·python·rust
Source.Liu12 小时前
【A11】项目架构设计笔记
rust
x-cmd12 小时前
用 Rust 打造 AI 时代的 SQL:把重复任务变成可执行文件
数据库·人工智能·sql·ai·容器·rust·workflow
铅笔侠_小龙虾1 天前
rust 学习(9):结构体
开发语言·学习·rust
铅笔侠_小龙虾1 天前
rust 学习(12):常用集合(上)-- Vec
rust