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

相关推荐
Ramble_Naylor10 小时前
Rust深度解读:Send 与 Sync 的本质与线程安全边界
python·算法·rust
Ramble_Naylor14 小时前
Rust深度解读:异步流(Async Streams)与生成器的处理艺术
开发语言·后端·rust
RobinDevNotes17 小时前
Memvid 把 Agent 长期记忆塞进一个文件
人工智能·rust·openresty
miofly19 小时前
GitHub 今日推荐|agent-desktop:通过无障碍树让 AI 代理直接操作桌面应用
rust·开源·github
geovindu19 小时前
rust:N-Barrier Pattern
开发语言·后端·设计模式·rust·屏障模式·并发型模式
Ramble_Naylor20 小时前
Rust深度解读:高性能 Web 网关与 Axum 架构剖析
前端·架构·rust
Hello.Reader21 小时前
100 人同时操作一座三维城市,为什么不需要服务器渲染 6000 帧?Rust + wgpu 多端并发架构实战
服务器·架构·rust
遇码1 天前
2026-11-01-daw-retry-banner-body
人工智能·ai·rust·数据分析·大模型·agent
不积跬步无以至千里mmbb261 天前
rust_analysis
开发语言·后端·rust
怪我冷i2 天前
Rust 的impl语法详解
开发语言·后端·rust