【Rust入门知识点学与练】第10课:Option 和 Result(错误处理入门)

知识点1:Option --- 处理"可能有值,也可能没有"的情况

Rust 没有 null,而是用 Option 枚举来表示"有值"或"没值":

rust 复制代码
fn main() {
    // Option 有两个变体:
    // Some(值) --- 有值
    // None     --- 没有值

    let score: Option<i32> = Some(95);
    let empty: Option<i32> = None;

    // 用 match 处理 Option
    match score {
        Some(s) => println!("分数是: {}", s),
        None => println!("没有分数"),
    }

    // 用 if let 简化(只关心有值的情况)
    if let Some(s) = score {
        println!("分数是: {}", s);
    }

    // 用 unwrap_or 提供默认值
    println!("分数: {}", score.unwrap_or(0));    // 95
    println!("分数: {}", empty.unwrap_or(0));    // 0

    // 用 is_some / is_none 判断
    println!("有值? {}", score.is_some());   // true
    println!("为空? {}", empty.is_none());   // true

    // 实际场景:Vec 的 pop 返回 Option
    let mut v = vec![1, 2, 3];
    match v.pop() {
        Some(val) => println!("弹出了: {}", val),
        None => println!("数组为空"),
    }
}

知识点2:Result --- 处理"可能出错"的操作

rust 复制代码
fn main() {
    // Result 有两个变体:
    // Ok(值)   --- 成功
    // Err(错误) --- 失败

    // 模拟一个可能失败的除法
    match divide(10, 2) {
        Ok(result) => println!("结果: {}", result),
        Err(e) => println!("错误: {}", e),
    }

    match divide(10, 0) {
        Ok(result) => println!("结果: {}", result),
        Err(e) => println!("错误: {}", e),
    }

    // 用 if let 只关心成功的情况
    if let Ok(result) = divide(10, 3) {
        println!("成功: {}", result);
    }
}

fn divide(a: i32, b: i32) -> Result<i32, String> {
    if b == 0 {
        Err(String::from("除数不能为0"))
    } else {
        Ok(a / b)
    }
}

核心规则

类型 变体 用途

Option Some(T) / None 值可能存在或不存在

Result<T, E> Ok(T) / Err(E) 操作可能成功或失败

处理方式 写法

match match x { Some(v) => ..., None => ... }

if let if let Some(v) = x { ... }

unwrap_or x.unwrap_or(默认值)

动手试试

补全下面的代码:

rust 复制代码
fn main() {
    // 补全:定义一个 find_item 函数,接收一个 Vec<i32> 和一个目标值 target
    // 如果找到目标值,返回 Some(索引)
    // 如果没找到,返回 None
    // 提示:用 for 循环遍历,记录索引

    let numbers = vec![10, 20, 30, 40, 50];

    // 补全:调用 find_item 查找 30,用 match 打印结果
    // 期望输出: 找到30,索引为: 2

    // 补全:调用 find_item 查找 99,用 match 打印结果
    // 期望输出: 没找到99

    // 补全:定义一个 safe_sqrt 函数,接收 f64 参数
    // 如果参数 >= 0,返回 Ok(平方根)
    // 如果参数 < 0,返回 Err(String::from("负数没有平方根"))
    // 提示:平方根用 x.sqrt()

    // 补全:调用 safe_sqrt(16.0),用 match 打印结果
    // 期望输出: 16的平方根: 4

    // 补全:调用 safe_sqrt(-4.0),用 match 打印结果
    // 期望输出: 错误: 负数没有平方根
}

期望输出:

找到30,索引为: 2

没找到99

16的平方根: 4

错误: 负数没有平方根

写好了贴过来,没问题就进入第11课:HashMap 键值对集合 👋

贴代码

rust 复制代码
  
fn main() {
    // 补全:定义一个 find_item 函数,接收一个 Vec<i32> 和一个目标值 target
    // 如果找到目标值,返回 Some(索引)
    // 如果没找到,返回 None
    // 提示:用 for 循环遍历,记录索引

    let numbers = vec![10, 20, 30, 40, 50];

    // 补全:调用 find_item 查找 30,用 match 打印结果
    // 期望输出: 找到30,索引为: 2

    // 补全:调用 find_item 查找 99,用 match 打印结果
    // 期望输出: 没找到99

    // 补全:定义一个 safe_sqrt 函数,接收 f64 参数
    // 如果参数 >= 0,返回 Ok(平方根)
    // 如果参数 < 0,返回 Err(String::from("负数没有平方根"))
    // 提示:平方根用 x.sqrt()

    // 补全:调用 safe_sqrt(16.0),用 match 打印结果
    // 期望输出: 16的平方根: 4

    // 补全:调用 safe_sqrt(-4.0),用 match 打印结果
    // 期望输出: 错误: 负数没有平方根
}

fn find_item(v: Vec<i32>, target: i32) -> Option<usize> {
    for (index, &val) in v.iter().enumerate() {
        if val == target {
            return Some(index);
        }
    }
    None
}

fn safe_sqrt(x: f64) -> Result<f64, String> {
    if x >= 0.0 {
        Ok(x.sqrt())
    } else {
        Err(String::from("负数没有平方根"))
    }
}

接下来把 main 里面调用和 match 补完整:

rust 复制代码
  
fn main() {
    let numbers = vec![10, 20, 30, 40, 50];

    // 查找30
    match find_item(numbers.clone(), 30) {
        Some(idx) => println!("找到30,索引为: {}", idx),
        None => println!("没找到30"),
    }

    // 查找99
    match find_item(numbers, 99) {
        Some(idx) => println!("找到99,索引为: {}", idx),
        None => println!("没找到99"),
    }

    // 平方根 16.0
    match safe_sqrt(16.0) {
        Ok(n) => println!("16的平方根: {}", n),
        Err(e) => println!("错误: {}", e),
    }

    // 平方根 -4.0
    match safe_sqrt(-4.0) {
        Ok(n) => println!("-4的平方根: {}", n),
        Err(e) => println!("错误: {}", e),
    }
}

fn find_item(v: Vec<i32>, target: i32) -> Option<usize> {
    for (index, &val) in v.iter().enumerate() {
        if val == target {
            return Some(index);
        }
    }
    None
}

fn safe_sqrt(x: f64) -> Result<f64, String> {
    if x >= 0.0 {
        Ok(x.sqrt())
    } else {
        Err(String::from("负数没有平方根"))
    }
}

运行输出:

plaintext

找到30,索引为: 2

没找到99

16的平方根: 4

错误: 负数没有平方根

核心知识点

  1. Option:代表可能有值、可能为空。 Some(值) / None 。常用于查找类函数。
  2. Result<T,E>:代表成功或者失败。 Ok(成功结果) / Err(错误信息) ,用于错误处理。
  3. .iter().enumerate() :同时拿到索引+元素,非常适合搜索位置。
  4. match:Rust 的模式匹配,专门用来拆开 Option / Result,两个分支必须写完整,不能漏。
  5. numbers.clone() :因为 find_item 获取 Vec 的所有权,第一次调用之后 numbers 就被移走了,第二次调用前需要克隆一份。

进阶提示:更好的写法是函数接收切片 &i32 , fn find_item(v: &i32, target:i32) ,就不需要 clone。初学阶段先用上面版本即可。

做完这道,Option、Result、match 基础就掌握了!

相关推荐
Dovis(誓平步青云)几秒前
启元 T1 Pro 人机相声搭档:语音-触摸双通道的启元机器人节奏引擎设计
开发语言·前端·javascript·microsoft·交互
做科研的周师兄3 分钟前
【R语言实战】MixSIAR 氢氧同位素水源解析全流程:从混合空间校验到贝叶斯 MCMC 收敛诊断(后附完整代码)
java·大数据·开发语言
.痞老板.1 小时前
java ee--计算机是如何工作的
java·开发语言·java-ee
奇树谦1 小时前
Qt Quick 图片加载与 GPU 纹理机制详解:QImage、QQuickTextureFactory、QSGTexture 与异步加载
开发语言·qt·系统架构
青梅味猪大肠2 小时前
【操作系统-60】临近适应算法
java·linux·开发语言·嵌入式硬件·算法·操作系统
Kapaseker2 小时前
Rust 不用写 for 循环?看我怎么写!
rust
starzy19903 小时前
深入理解Scala可变Map:动态构建场景下的性能与设计权衡
开发语言·scala
奶油话梅糖3 小时前
打开项目 0.9 秒、内存只有 IDEA 的 1/12:OpenIDEA 用 Rust 把 IntelliJ IDEA 重造了一遍
java·rust·github·intellij-idea
zhanghaha13144 小时前
C# 系列教程_7 判断语句(分支)保姆级精讲
开发语言·c#
apcipot_rain4 小时前
C++转Java日记(02)
java·开发语言·c++