Rust 初体验4

《Rust语言圣经》入门实战的前两节中,介绍了 minigrep 程序设计过程,包括命令行设计、参数接收、文件读取、模块化和错误处理等。其功能是从指定文件中查找字符串。

代码包括两部分:main.rs,lib.rs。下面对代码简单做了注释。

main.rs

// 引入标准库中的环境变量和进程处理模块
use std::env;
use std::process;
// 引入自定义的minigrep模块中的Config结构体
use minigrep::Config;

// 主函数
fn main() {
    // 获取命令行参数并存储到Vec类型的args中
    let args: Vec<String> = env::args().collect();
    // 使用Config::build方法解析命令行参数,如果解析失败则打印错误信息并退出程序
    let config = Config::build(&args).unwrap_or_else(|err|{
        println!("Problem parsing arguments: {}", err);
        process::exit(1)
    });
    // 打印搜索关键词和文件名
    println!("Searching for {}", config.query);
    println!(" in file {}", config.filename);
    // 调用minigrep模块的run方法执行搜索操作,如果发生错误则打印错误信息并退出程序
    if let Err(e) = minigrep::run(config){
        println!("Application error: {}", e);
        process::exit(1);
    }
    // 程序正常结束,退出状态码为0
    process::exit(0);
}

lib 模块

// 导入标准库中的文件系统模块和错误处理模块
use std::fs;
use std::error::Error;

// 定义一个名为Config的结构体,包含两个公共字段:query和filename
pub struct Config {
    pub query: String,
    pub filename: String,
}

// 为Config结构体实现一个名为build的方法,接收一个字符串切片作为参数,返回Result类型
impl Config{
    // build方法用于根据传入的参数构建Config实例
    pub fn build(args: &[String]) -> Result<Config, &'static str> {
        // 如果参数数量小于3,返回错误信息
        if args.len() < 3 {
            return Err("Not enough arguments");
        }
        // 获取查询字符串和文件名
        let query = args[1].clone();
        let filename = args[2].clone();
        // 返回构建好的Config实例
        Ok(Config{ query, filename })
    }
}

// 定义一个名为run的函数,接收一个Config实例作为参数,返回Result类型
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
    // 读取文件内容到字符串中,如果出错则抛出异常
    let contents = fs::read_to_string(config.filename) 
        .expect("Something went wrong reading the file");
    // 打印文件内容
    println!("With text:{}", contents);
    // 返回成功
    Ok(())
}

代码说明

main.rs模块

  1. 引入了标准库中的环境变量和进程处理模块。
  2. 引入了自定义的minigrep模块中的Config结构体。
  3. 定义了主函数main()。
  4. 获取命令行参数并存储到Vec类型的args中。
  5. 使用Config::build方法解析命令行参数,如果解析失败则打印错误信息并退出程序。
  6. 打印搜索关键词和文件名。
  7. 调用minigrep模块的run方法执行搜索操作,如果发生错误则打印错误信息并退出程序。
  8. 程序正常结束,退出状态码为0。

lib.rs模块

  1. 导入了标准库中的文件系统模块和错误处理模块。
  2. 定义了一个名为Config的结构体,包含两个公共字段:query和filename。
  3. 为Config结构体实现了一个名为build的方法,接收一个字符串切片作为参数,返回Result类型。该方法用于根据传入的参数构建Config实例。
  4. 定义了一个名为run的函数,接收一个Config实例作为参数,返回Result类型。该函数用于读取文件内容并在控制台打印出来。

关于错误处理

在以上代码中,错误处理主要通过Result类型和unwrap_or_else方法来实现。

  1. Result类型:用于表示一个操作可能成功或失败的结果。它有两个变体:Ok表示操作成功,并包含成功时的值;Err表示操作失败,并包含失败的原因。

  2. unwrap_or_else方法:该方法用于处理Result类型的结果。如果结果是Ok,则返回Ok中的值;如果结果是Err,则执行传入的闭包函数,并返回该函数的结果。在这个例子中,当Config::build方法返回Err时,会执行闭包函数,打印错误信息并退出程序。

例如,在main.rs模块中,以下代码段:

let config = Config::build(&args).unwrap_or_else(|err|{
    println!("Problem parsing arguments: {}", err);
    process::exit(1)
});

这里使用了unwrap_or_else方法来处理Config::build方法的返回结果。如果build方法返回Ok,那么config变量将被赋值为Ok中的Config实例;如果build方法返回Err,那么将执行闭包函数,打印错误信息并退出程序。

lib.rs模块中:

if let Err(e) = minigrep::run(config){
    println!("Application error: {}", e);
    process::exit(1);
}

这里使用了if let语句来处理minigrep::run方法的返回结果。如果run方法返回Ok,那么程序将继续执行;如果run方法返回Err,那么将执行闭包函数,打印错误信息并退出程序。

Result 泛型

Result<(), Box> 是一个泛型类型,用于表示一个操作可能成功或失败的结果。它有两个变体:Ok表示操作成功,并包含成功时的值;Err表示操作失败,并包含失败的原因。

在这个例子中,Result的类型参数是(),表示操作成功时没有返回值。错误类型是Box,其中Box表示一个堆分配的指针,而dyn Error表示任何实现了Error trait的类型。这意味着这个Result可以容纳任何实现了Error trait的错误类型。

这种类型的Result通常用于那些不需要返回具体值的操作,只需要表示操作是否成功。例如,在minigrep::run函数中,它返回Result<(), Box>,表示该函数执行搜索操作,如果成功则不返回任何值(Ok(())),如果失败则返回一个实现了Error trait的错误类型(Err(error))

关于Error trait

Rust中用于表示错误的标准接口。它定义了一组方法,用于处理错误和获取关于错误的信息。Error trait 常用方法:

  1. description:返回一个字符串切片,描述了错误的细节。
  2. cause:返回一个Option类型的值,包含导致当前错误的原始错误。如果当前错误没有原因,则返回None。
  3. source:返回一个Option类型的值,包含导致当前错误的原始错误。与cause方法类似,但source方法提供了更多的上下文信息。
  4. chain:返回一个Option类型的值,包含一个错误链表,描述了导致当前错误的多个原始错误。如果当前错误没有原因,则返回None。
  5. backtrace:返回一个Option类型的值,包含当前错误的回溯信息。这对于调试和定位错误非常有用。
  6. to_string:返回一个字符串,包含了关于当前错误的详细信息。这个字符串通常包含了description、cause、source、chain和backtrace等方法的信息。

要实现Error trait,类型需要提供上述方法的具体实现。Rust的标准库中已经为许多内置类型实现了Error trait,例如std::io::Error、std::num::ParseIntError等。用户也可以为自己的类型实现Error trait,以便在错误处理中使用。

你可能感兴趣的:(rust,开发语言)