【Rust 基础入门】(14) | 错误处理

  • 0xE
  • 发布于 5天前
  • 阅读 241

本文介绍了Rust中的错误处理机制,通过温度检查的示例展示了不可恢复的 Panic 和可恢复的 Result 的使用,讲解了 ? 运算符简化错误传播的方法及其意义。

Rust 将错误分为两类:不可恢复错误(panic)和可恢复错误(Result)。想象你正在组装一架模型飞机:如果发现缺少关键零件,组装无法继续,只能停下来检查问题,这就是不可恢复的 panic;但如果只是螺丝拧不紧,你可以换个工具继续尝试,这就是可恢复的 Result。


不可恢复错误 - Panic

不可恢复错误通常意味着程序遇到了无法继续运行的情况,比如访问超出数组范围或断言失败。在Rust中,我们可以用 panic! 宏显式触发这种错误。当 panic 发生时,程序会打印错误信息,清理栈上的资源(通过栈展开),然后退出。

触发Panic

假设我们在计算一个数的平方根时,要求输入必须是非负数:

fn square_root(n: f64) {
    if n < 0.0 {
        panic!("Cannot compute square root of a negative number: {}", n);
    }
    println!("Square root of {} is {}", n, n.sqrt());
}

fn main() {
    square_root(4.0);  // 输出: Square root of 4 is 2
    square_root(-1.0);  // panic! 程序终止,打印错误信息
}

运行这段代码时,传入负数,panic! 会中断程序。


可恢复错误 - Result

对于可以预见和处理的错误,Rust 提供了 Result<T, E> 类型。它是一个枚举,定义如下:

enum Result&lt;T, E> {
    Ok(T),  // 成功时返回的值
    Err(E),  // 失败时的错误信息
}

使用Result

假设我们要检查一个温度是否在安全范围内:

fn check_temperature(temp: f64) -> Result&lt;f64, String> {
    if temp > 100.0 {
        Err(format!("Temperature {}°C is too high!", temp))
    } else if temp &lt; -50.0 {
        Err(format!("Temperature {}°C is too low!", temp))
    } else {
        Ok(temp)
    }
}

fn main() {
    let temp = check_temperature(25.0);
    match temp {
        Ok(value) => println!("Safe temperature: {}°C", value),
        Err(msg) => println!("Error: {}", msg),
    }

    let too_hot = check_temperature(150.0);
    match too_hot {
        Ok(value) => println!("Safe temperature: {}°C", value),
        Err(msg) => println!("Error: {}", msg),
    }
}

输出:

Safe temperature: 25°C
Error: Temperature 150°C is too high!

这里,Result让我们既能处理成功的情况(Ok),也能捕获错误(Err),避免程序直接崩溃。


错误传播与简化

手动用 match 处理 Result 虽然可行,但代码很容易变得冗长。Rust 提供了 ? 运算符,像一个自动化的助手,把错误传播给调用者,同时简化成功情况的处理。

使用 ? 运算符

假设我们要组合两个检查步骤:温度和湿度:

fn check_temperature(temp: f64) -> Result&lt;f64, String> {
    if temp > 100.0 {
        Err(format!("Temperature {}°C is too high!", temp))
    } else if temp &lt; -50.0 {
        Err(format!("Temperature {}°C is too low!", temp))
    } else {
        Ok(temp)
    }
}

fn check_humidity(humidity: f64) -> Result&lt;f64, String> {
    if humidity > 90.0 {
        Err(format!("Humidity {}% is too high!", humidity))
    } else if humidity &lt; 10.0 {
        Err(format!("Humidity {}% is too low!", humidity))
    } else {
        Ok(humidity)
    }
}

fn check_conditions(temp: f64, humidity: f64) -> Result&lt;String, String> {
    let safe_temp = check_temperature(temp)?;  // 如果出错,传播错误
    let safe_humidity = check_humidity(humidity)?;  // 如果出错,传播错误
    Ok(format!("Conditions safe: {}°C, {}%", safe_temp, safe_humidity))
}

fn main() {
    match check_conditions(25.0, 50.0) {
        Ok(result) => println!("{}", result),
        Err(e) => println!("Error: {}", e),
    }

    match check_conditions(150.0, 50.0) {
        Ok(result) => println!("{}", result),
        Err(e) => println!("Error: {}", e),
    }
}

输出:

Conditions safe: 25°C, 50%
Error: Temperature 150°C is too high!

? 运算符在这里起到了关键作用:如果 check_temperature 或 check_humidity 返回 Err,错误会直接传播给 main,否则返回值被解包为 Ok 中的内容。这种方式让代码更简洁。


小结

  • Panic 用于不可恢复错误,直接终止程序,适合致命问题。
  • Result 处理可恢复错误,通过 Ok 和 Err 提供灵活性。
  • ?运算符 简化错误传播,减少样板代码。
  • 错误传播让调用者根据上下文决定处理方式。
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
0xE
0xE
0x59f6...a17e
17年进入币圈,Web3 开发者。刨根问底探链上真相,品味坎坷悟 Web3 人生。有工作机会可加v:__0xE__