【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 基础就掌握了!

相关推荐
喵的前端路41 分钟前
《EDVAC》学习记录(第二部分)
学习
leonkay1 小时前
C# 锁机制——【2】深入原理
开发语言·后端·spring·c#·个人开发
lee_curry1 小时前
AI Agent 工程师完整学习路线(面向生产级项目与面试)
人工智能·学习·ai·面试·agent
小毛驴8501 小时前
前端开发学习路线可以分为几个层次
学习
坐吃山猪1 小时前
【多线程】CompletableFuture使用
java·开发语言·多线程
star learning white1 小时前
STM32入门学习3
stm32·单片机·学习
浔溺1 小时前
al+大数据每日学习笔记31
大数据·笔记·学习
!!!!8131 小时前
AI Coding学习
学习
山岚的运维笔记1 小时前
mysql 专业笔记 -- 第 8 章:使用变量
运维·数据库·笔记·后端·学习·mysql·dba