..

Rust 学习笔记(4)

学习Rust的第四天,错误处理。

基于 Result 的错误处理

错误处理的核心数据结构:

enum Result<T, E> {
    Ok(T),
    Err(E),
}

以文件打开为例:

use std::fs::File;

fn main() {
    let f = File::open("hello.txt");

    let nf = match f {
        Ok(file) => file, // 🆗 返回 std::fs::File
        Err(error) => panic!("Problem opening the file: {:?}", error), // ⭕ 错误程序 panic
    };
}

注意: nf 的类型由 Ok 和 Err 的返回值推断,因此两个返回值的类型必须一致:

let f = File::open("hello.txt");

let nf = match f {
    Ok(file) => file, // nf 类型推断为 std::fs::File
    Err(error) => "not ok" // nf 类型推断为 &str,编译错误 ❌
};

unwrapexpect 就是遇到错误panic的语法糖函数:

let f = File::open("hello.txt").unwrap();
let f = File::open("hello.txt").expect("Failed to open hello.txt"); // expect 可以传入定制的panic消息

返回错误

函数返回包含错误的 Result 的返回值:

use std::fs::File;

fn read_username_from_file() -> Result<String, io::Error> {
    let f = File::open("hello.txt");

    let mut f = match f {
        Ok(file) => file,
        Err(e) => return Err(e), // ⭕ 提前中止函数并且返回错误
    };

    let mut s = String::new();

    match f.read_to_string(&mut s) {
        Ok(_) => Ok(s), // 🆗 执行成功,返回包含 String 值的 Result
        Err(e) => Err(e), // ⭕ 执行错误,返回包含 Err 的 Result
    }
}

? 放在返回 Result 函数的最后,Ok 时返回 T,Err 时中止当前作用域的函数,并返回错误。 利用语法糖 ?,上面的例子重构为:

use std::fs::File;
use std::io::{self, Read};

fn read_username_from_file() -> Result<String, io::Error> {
    let mut f = File::open("hello.txt")?;
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}

? 做链式调用:

fn read_username_from_file() -> Result<String, io::Error> {
    let mut s = String::new();

    File::open("hello.txt")?.read_to_string(&mut s)?;

    Ok(s)
}

? 也适用于返回 Option 函数:

fn last_char_of_first_line(text: &str) -> Option<char> {
    text.lines().next()?.chars().last() // 如果 next 函数返回 None 将中止整个函数,并且返回 None
}