Rust学习记录--C12 实例:写一个命令行程序

C12 实例:写一个命令行程序

  • [1. 读取命令行参数](#1. 读取命令行参数)
  • [2. 读取文件](#2. 读取文件)
  • [3. 处理错误](#3. 处理错误)
    • [3.1 处理传入参数可能导致的错误](#3.1 处理传入参数可能导致的错误)
    • [3.2 处理一些标准错误,类似于文件读取错误等等](#3.2 处理一些标准错误,类似于文件读取错误等等)
    • [3.3 在调用函数时如何处理潜在的exception](#3.3 在调用函数时如何处理潜在的exception)
  • [4. 重构->增进模块](#4. 重构->增进模块)
  • [5. 使用测试驱动开发](#5. 使用测试驱动开发)
  • [6. 错误处理代码集中放置,方便后期修改](#6. 错误处理代码集中放置,方便后期修改)
  • [7. 具体实现](#7. 具体实现)

要求:在一个文件中搜索字符串返回对应的行的列表

1. 读取命令行参数

use std::env::args() // 并且使用collect() 转换为Vec<String>

rust 复制代码
let args : Vec<String> = env::args().collect();

2. 读取文件

use std::fs::read_to_string()

rust 复制代码
let file_content = fs::read_to_string(config.filename)?;

3. 处理错误

3.1 处理传入参数可能导致的错误

使用

rust 复制代码
Result<Configuration, &'static str>

例子:

rust 复制代码
pub fn new(args: &[String]) -> Result<Configuration, &'static str>{
    if args.len() < 3 {
        return Err("The input args should be 2")
    }

    let query = args[1].clone();
    let filename = args[2].clone();
    Ok(Configuration { query, filename })
}

3.2 处理一些标准错误,类似于文件读取错误等等

在表达式结尾加上?

返回类型:

rust 复制代码
Result<(), Box<dyn Error>>

例子:

rust 复制代码
pub fn run(config: Configuration) -> Result<(), Box<dyn Error>> {
   
    let file_content = fs::read_to_string(config.filename)?;

    for item in search(&config.query, &file_content)
    {
        println!("The query: '{}' in : {}", config.query, item);
    }
    Ok(())
}

3.3 在调用函数时如何处理潜在的exception

针对返回结果是Result<T,E>的类型,使用if let

rust 复制代码
    if let Err(e) = App::run(config) {
        println!("Application error: {}",e);
        process::exit(1);
    }

4. 重构->增进模块

  • 配置变量放在一个结构体中
    • 搞出一个结构体,并设置new函数
  • 每个函数只负责一个功能

5. 使用测试驱动开发

  • 通过写测试的方式实现开发

  • 逻辑

    • 编写一个会失败的测试,运行该测试,确保它是按照预期的原因失败(在此期间,确认调用的函数输入和输出)
    • 编写或修改刚好足够的代码,让测试通过
    • 重构刚刚添加或修改的代码,确保测试会始终测试通过
    • 返回步骤1,继续
  • 新的开发:实现区分大小写和不区分大小写的两种search,并且将环境变量作为该功能的开关

    • 来自环境变量:use std::env::var("环境变量的名称")
    rust 复制代码
    // 只要出现CASE_INSENSITIVE,就认为是不区分大小写的,不出现就表示区分大小写
    // env::var("CASE_INSENSITIVE")的返回结果是Result
    let case_sensitive = env::var("CASE_INSENSITIVE").is_err();

6. 错误处理代码集中放置,方便后期修改

  • 区分标准错误和标准输出
    • 标准输出:stdout
      • println!
    • 标准错误:stderr
      • eprintln!
  • cargo run > output.txt

7. 具体实现

rust 复制代码
// main.rs
use std::{env, process};

use App::Configuration;

fn main() {    
    let args : Vec<String> = env::args().collect();

    let config = Configuration::new(&args).unwrap_or_else(|err| {
        eprintln!("Problem pasing arg: {}", err);
        process::exit(-1);
    });

    if let Err(e) = App::run(config) {
        eprintln!("Application error: {}", e);
        process::exit(-1);
    }
}
rust 复制代码
// lib.rs
use std::error::Error;
use std::fs;
use std::env;

pub struct Configuration {
    pub query: String,
    pub filename: String,
    pub case_sensitive: bool,
}

impl Configuration {
    pub fn new(args: &[String]) -> Result<Configuration, &'static str>{
        if args.len() < 3 {
            return Err("The input args should be 2")
        }

        let query = args[1].clone();
        let filename = args[2].clone();
        let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
        Ok(Configuration { query, filename, case_sensitive })
    }
}

pub fn run(config: Configuration) -> Result<(), Box<dyn Error>> {
    
    let file_content = fs::read_to_string(config.filename)?;

    let res = if config.case_sensitive {
        search_sensitive(&config.query, &file_content)
    } else {
        search_insensitive(&config.query, &file_content)        
    };

    for item in res
    {
        eprintln!("The query: '{}' in : {}", config.query, item);
    }
    Ok(())
}

pub fn search_insensitive<'a>(query: &str, content: &'a str) -> Vec<&'a str> {
    let mut vec = Vec::new();
    for item in content.lines() {
        if item.to_lowercase().contains(&query.to_lowercase())
        {
            vec.push(item);
        }
    }
    vec
}


pub fn search_sensitive<'a>(query: &str, content: &'a str) -> Vec<&'a str> {
    let mut vec = Vec::new();
    for item in content.lines() {
        if item.contains(query)
        {
            vec.push(item);
        }
    }
    vec
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn one_result_sensitive() {
        let query = "streeT";
        let content = "\
        The morning sun painted the sky with soft orange light.
Birds sang quietly while the city slowly came awake.
A gentle breeze moved leaves along the empty streeT.
Coffee shops opened doors, releasing warm familiar street.";
        assert_eq!(
            vec!["A gentle breeze moved leaves along the empty streeT."], 
            search_sensitive(query, content));
    }

    #[test]
    fn one_result_insensitive() {
        let query = "streeT";
        let content = "\
        The morning sun painted the sky with soft orange light.
Birds sang quietly while the city slowly came awake.
A gentle breeze moved leaves along the empty streeT.
Coffee shops opened doors, releasing warm familiar street.";
        assert_eq!(
            vec!["A gentle breeze moved leaves along the empty streeT.", "Coffee shops opened doors, releasing warm familiar street."], 
            search_insensitive(query, content));
    }
}
相关推荐
大柏怎么被偷了2 小时前
【C++】哈希桶
数据结构·算法·哈希算法
leaves falling2 小时前
c语言自定义类型深度解析:联合(Union)与枚举(Enum)
c语言·开发语言·算法
DBBH2 小时前
DBBH的AI学习笔记
人工智能·笔记·学习
青衫码上行2 小时前
如何构建maven项目
java·学习·maven
June bug2 小时前
【实习笔记】正交实验法设计测试用例
笔记·学习·测试用例
期末考复习中,蓝桥杯都没时间学了2 小时前
力扣刷题记录2
算法·leetcode·职场和发展
高洁012 小时前
知识图谱如何结合 RAG实现更精确的知识问答
人工智能·算法·机器学习·数据挖掘·知识图谱
爱喝可乐的老王2 小时前
机器学习监督学习模型----KNN
人工智能·算法·机器学习
丝斯20112 小时前
AI学习笔记整理(54)——大模型之Agent 智能体开发前沿技术
人工智能·笔记·学习