Rust之构建命令行程序(五):环境变量

开发环境

  • Windows 11
  • Rust 1.77.0 
  • VS Code 1.87.2

项目工程

这次创建了新的工程minigrep.

 使用环境变量

我们将通过添加一个额外的功能来改进minigrep:一个不区分大小写的搜索选项,用户可以通过环境变量打开该选项。我们可以将此功能设置为命令行选项,并要求用户在每次想要应用它时输入它,但通过将其设置为环境变量,我们允许用户设置一次环境变量,并在该终端会话中使他们的所有搜索不区分大小写。

为不区分大小写的search函数编写失败测试

我们首先添加一个新的search_case_insensitive函数,当环境变量有值时将调用该函数。我们将继续遵循TDD过程,所以第一步是再次编写一个失败的测试。我们将为新的search_case_insensitive函数添加一个新测试,并将我们的旧测试从one_result重命名为case_sensitive,以阐明两个测试之间的差异,如示例12-20所示。

文件名:src/lib.rs

#[cfg(test)]
mod tests {use super::*;#[test]fn case_sensitive() {let query = "duct";let contents = "\
Rust:
safe, fast, productive.
Pick three.
Duct tape.";assert_eq!(vec!["safe, fast, productive."], search(query, contents));}#[test]fn case_insensitive() {let query = "rUsT";let contents = "\
Rust:
safe, fast, productive.
Pick three.
Trust me.";assert_eq!(vec!["Rust:", "Trust me."],search_case_insensitive(query, contents));}
}

 示例12-20:为我们将要添加的不区分大小写的函数添加新的失败测试

请注意,我们还编辑了旧测试的contents。我们添加了一个新行,文本为“Duct tape”当我们以区分大小写的方式进行搜索时,使用不应该与查询“duct”匹配的大写D。以这种方式更改旧测试有助于确保我们不会意外破坏已经实现的区分大小写的搜索功能。这个测试现在应该通过了,并且在我们进行不区分大小写的搜索时应该会继续通过。

不区分大小写搜索的新测试使用“rUsT”作为查询。在我们即将添加的search_case_insensitive函数中,查询“Rust:”应该与包含大写R的行“rUsT:”匹配,并与行“Trust me”匹配。即使两者的大小写与查询不同。这是我们失败的测试,它将无法编译,因为我们还没有定义search_case_insensitive函数。随意添加一个总是返回空向量的框架实现,类似于我们对示例12-16中的search函数所做的那样,以查看测试编译和失败。

实现search_case_insensitive函数 

示例12-21所示的search_case_insensitive函数与search函数几乎相同。唯一的区别是我们将queryline都小写,因此无论输入参数的大小写如何,当我们检查该行是否包含查询时,它们都是相同的大小写。

文件名:src/lib.rs

pub fn search_case_insensitive<'a>(query: &str,contents: &'a str,
) -> Vec<&'a str> {let query = query.to_lowercase();let mut results = Vec::new();for line in contents.lines() {if line.to_lowercase().contains(&query) {results.push(line);}}results
}

 示例12-21:定义search_case_insensitive函数在比较查询和行之前将其小写

首先,我们将query字符串小写,并将其存储在同名的隐藏变量中。对查询调用to_lowercase是必要的,因此无论用户的查询是“rust”、“Rust”、“rUsT”还是“rust”,我们都将查询视为“RUST”,并且不区分大小写。虽然to_lowercase可以处理基本的Unicode,但它不会100%准确。如果我们正在编写一个真正的应用程序,我们会想在这里多做一点工作,但这一节是关于环境变量的,而不是Unicode,所以我们将把它留在这里。

请注意,query现在是String而不是字符串片段,因为调用to_lowercase会创建新数据而不是引用现有数据。例如,假设查询是“rUsT”:该字符串片段不包含供我们使用的小写ut,因此我们必须分配一个包含“rust”的新String。当我们现在将query作为参数传递给contains方法时,我们需要添加一个&符号,因为contains的签名被定义为接受一个字符串切片。

接下来,我们在line添加一个对to_lowercase的调用,以小写所有字符。现在我们已经将linequery转换为小写,无论查询的大小写如何,我们都将找到匹配项。 

让我们看看这个实现是否通过了测试: 

$ cargo testCompiling minigrep v0.1.0 (file:///projects/minigrep)Finished test [unoptimized + debuginfo] target(s) in 1.33sRunning unittests src/lib.rs (target/debug/deps/minigrep-9cd200e5fac0fc94)running 2 tests
test tests::case_insensitive ... ok
test tests::case_sensitive ... oktest result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sRunning unittests src/main.rs (target/debug/deps/minigrep-9cd200e5fac0fc94)running 0 teststest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00sDoc-tests minigreprunning 0 teststest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

 太好了!他们通过了。现在,让我们从run函数中调用新的search_case_insensitive函数。首先,我们将向Config结构添加一个配置选项,以在区分大小写和不区分大小写的搜索之间切换。添加此字段将导致编译器错误,因为我们还没有在任何地方初始化此字段:

文件名:src/lib.rs

pub struct Config {pub query: String,pub file_path: String,pub ignore_case: bool,
}

 我们添加了包含布尔值的ignore_case字段。接下来,我们需要run函数来检查ignore_case字段的值,并使用它来决定是调用search函数还是search_case_insensitive函数,如示例12-22所示。这仍然无法编译。

文件名:src/lib.rs

pub fn run(config: Config) -> Result<(), Box<dyn Error>> {let contents = fs::read_to_string(config.file_path)?;let results = if config.ignore_case {search_case_insensitive(&config.query, &contents)} else {search(&config.query, &contents)};for line in results {println!("{line}");}Ok(())
}

清单12-22:根据config.ignore_case中的值调用searchsearch_case_insensitive

最后,我们需要检查环境变量。处理环境变量的函数在标准库中的env模块中,因此我们将该模块纳入src/lib.rs的顶部。然后我们将使用env模块中的var函数来检查是否为名为IGNORE_CASE的环境变量设置了任何值,如示例12-23所示。 

文件名:src/lib.rs 

use std::env;
// --snip--impl Config {pub fn build(args: &[String]) -> Result<Config, &'static str> {if args.len() < 3 {return Err("not enough arguments");}let query = args[1].clone();let file_path = args[2].clone();let ignore_case = env::var("IGNORE_CASE").is_ok();Ok(Config {query,file_path,ignore_case,})}
}

清单12-23:检查名为IGNORE_CASE的环境变量中的任何值

在这里,我们创建了一个新变量ignore_case。为了设置其值,我们调用env::var函数并向其传递IGNORE_CASE环境变量的名称。如果环境变量设置为任意值,env::var函数返回的Result将是成功的Ok变量,该变量包含环境变量的值。如果未设置环境变量,它将返回Err变量。 

我们对Result使用is_ok方法来检查是否设置了环境变量,这意味着程序应该进行不区分大小写的搜索。如果IGNORE_CASE环境变量未设置为任何值,is_ok将返回false,程序将执行区分大小写的搜索。我们不关心环境变量的值,只关心它是设置的还是未设置的,因此我们检查的是is_ok,而不是使用unwrapexpect或我们在Result上看到的任何其他方法。 

我们将ignore_case变量中的值传递给Config实例,这样run函数就可以读取该值并决定是调用search_case_insensitive还是search,如示例12-22所示。 

完整源码

文件名:src/lib.rs 

pub mod cfg {use std::error::Error;use std::env;use std::fs;pub struct Config {pub query: String,pub file_path: String,pub ignore_case: bool,}impl Config {pub fn build(args: &[String]) -> Result<Config, &'static str> {if args.len() < 3 {return Err("not enough arguments");}let query = args[1].clone();let file_path = args[2].clone();let ignore_case = env::var("IGNORE_CASE").is_ok();Ok(Config {query,file_path,ignore_case,})}}#[cfg(test)]
mod tests {use super::*;#[test]fn case_sensitive() {let query = "duct";let contents = "\Rust:safe, fast, productive.Pick three.Duct tape.";assert_eq!(vec!["safe, fast, productive."], search(query, contents));}#[test]fn case_insensitive() {let query = "rUsT";let contents = "\Rust:safe, fast, productive.Pick three.Trust me.";assert_eq!(vec!["Rust:", "Trust me."],search_case_insensitive(query, contents));}
}pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {let mut results = Vec::new();for line in contents.lines() {if line.contains(query) {results.push(line);}}results}pub fn search_case_insensitive<'a>(query: &str,contents: &'a str,) -> Vec<&'a str> {let query = query.to_lowercase();let mut results = Vec::new();for line in contents.lines() {if line.to_lowercase().contains(&query) {results.push(line);}}results}pub fn run(config: Config) -> Result<(), Box<dyn Error>> {let contents = fs::read_to_string(config.file_path)?;let results = if config.ignore_case {search_case_insensitive(&config.query, &contents)} else {search(&config.query, &contents)};for line in results {println!("{line}");}Ok(())}
}

文件名:src/main.rs  

use std::env;
use std::process;
use minigrep::cfg;fn main() {let args: Vec<String> = env::args().collect();let config = cfg::Config::build(&args).unwrap_or_else(|err| {println!("Problem parsing arguments: {err}");process::exit(1);});println!("Searching for {}", config.query);println!("In file {}", config.file_path);if let Err(e) = cfg::run(config) {println!("Application error: {e}");process::exit(1);} 
}

让我们试一试吧!首先,我们将在不设置环境变量的情况下运行我们的程序,并使用to查询,该查询应匹配包含全部小写单词“to”的任何行: 

$ cargo run -- to poem.txtCompiling minigrep v0.1.0 (file:///projects/minigrep)Finished dev [unoptimized + debuginfo] target(s) in 0.0sRunning `target/debug/minigrep to poem.txt`
Are you nobody, too?
How dreary to be somebody!

 看来这仍然有效!现在,让我们运行程序,将IGNORE_CASE设置为1,但仍然使用to

$ IGNORE_CASE=1 cargo run -- to poem.txt

 如果您使用的是PowerShell,则需要设置环境变量并作为单独的命令运行程序:

PS> $Env:IGNORE_CASE=1; cargo run -- to poem.txt

 这将使IGNORE_CASE在shell会话的剩余部分持续存在。可以使用Remove-Item cmdlet取消设置它:

PS> Remove-Item Env:IGNORE_CASE

 我们应该得到包含“to”的行,这些行可能包含大写字母:

Are you nobody, too?
How dreary to be somebody!
To tell your name the livelong day
To an admiring bog!

 太好了,我们还得到了包含“To”的行!我们的minigrep程序现在可以进行由环境变量控制的不区分大小写的搜索。现在您知道了如何使用命令行参数或环境变量来管理选项集。

一些程序允许相同配置的参数和环境变量。在这些情况下,程序会决定其中一个优先。对于您自己的另一个练习,尝试通过命令行参数或环境变量来控制大小写。如果程序运行时一个设置为区分大小写,一个设置为忽略大小写,请确定是命令行参数还是环境变量优先。 

std::env模块包含许多更有用的处理环境变量的特性:查看其文档以了解可用的特性。 

本章重点

  • 环境变量的意义
  • 编写不区分大小写的search函数
  • 不区分大小写search函数的实现思路
  • 通过添加环境变量的方式实现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/764954.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uniapp(vue3) H5页面连接打印机并打印

一、找到对应厂商打印机的驱动并在windows上面安装。查看是否安装完成可以在&#xff1a;控制面板->查看设备和打印机&#xff0c;找到对应打印机驱动是否安装完成 二、打印机USB连接电脑 三、运行代码调用浏览器打印&#xff0c;主要使用的是window.print()功能。下面使用…

前端学习笔记 | Node.js

一、Node.js入门 1、什么是Node.js 定义&#xff1a;是跨平台JS运行环境&#xff08;可以独立执行JS的环境&#xff09;作用&#xff1a; 编写数据接口&#xff0c;提供网页资源功能等等前端工程化&#xff1a;为后续学Vue和React等框架做铺垫 2、Node.js为何能执行JS&#xff…

python分类信息服务平台移动端的设计与实现flask-django-php-nodejs

分类信息服务平台设计的目的是为用户提供活动信息、活动记录等方面的平台。 与PC端应用程序相比&#xff0c;分类信息服务平台的设计主要面向于移动端&#xff0c;旨在为管理员和用户、商铺提供一个分类信息服务平台。用户可以通过Android及时查看活动信息等。 分类信息服务平台…

IDEA调优-四大基础配置-编码纵享丝滑

文章目录 1.JVM虚拟机选项配置2.多线程编译速度3.构建共享堆内存大小4.关闭不必要的插件 1.JVM虚拟机选项配置 -Xms128m -Xmx8192m -XX:ReservedCodeCacheSize1024m -XX:UseG1GC -XX:SoftRefLRUPolicyMSPerMB50 -XX:CICompilerCount2 -XX:HeapDumpOnOutOfMemoryError -XX:-Omi…

pytest之fixture结合conftest.py文件使用+断言实战

pytest之fixture结合conftest.py文件使用 conftest.py--存放固件固件的优先级pytest执行流程pytest之断言实战pytest结合allure-pytest插件生成美观的报告 conftest.py–存放固件 在一个项目的测试中&#xff0c;大多数情况下会有多个类、模块、或者包要使用相同的测试夹具。这…

kafka2.x版本配置SSL进行加密和身份验证

背景&#xff1a;找了一圈资料&#xff0c;都是东讲讲西讲讲&#xff0c;最后我还没搞好&#xff0c;最终决定参考官网说明。 官网指导手册地址&#xff1a;Apache Kafka 需要预备的知识&#xff0c;keytool和openssl 关于keytool的参考&#xff1a;keytool的使用-CSDN博客 …

Pytest测试框架+allure+jenkins自动化持续集成

Pytest是python的一种单元测试框架&#xff0c;可通过pytest 目录路径来运行测试用例 可以通过断言assert来测试是否通过 1.pytest测试用例命名规范 需严格遵循此规范&#xff0c;不然使用 pytest 目录 来运行会找不到该条测试用例。 可通过这样定义main函数&#xf…

Redis入门到实战-第二弹

Redis入门到实战 Redis安装官网地址Redis概述Redis-server安装Redis-stack-server使用(可选)Redisinsight安装(可选)更新计划 Redis安装 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https://redis.io/Redis概述 Redis是…

LabVIEW焓差试验室流量计现场自动校准系统

LabVIEW焓差试验室流量计现场自动校准系统 在现代工业和科研领域&#xff0c;流量计的准确性对于保证生产过程的质量和效率非常重要。开发了一种基于LabVIEW的焓差试验室流量计现场自动校准系统&#xff0c;通过提高流量计校准的准确性和效率。 在空调器空气焓值法能效测量装…

java网络原理(二)------TCP确认应答和超时重传

一Tcp协议 TCP&#xff0c;即Transmission Control Protocol&#xff0c;传输控制协议。人如其名&#xff0c;要对数据的传输进行一个详细的控制。 二.TCP协议段格式 知道了端口号才能进一步确认这个数据报交给了哪一个程序。16为端口号是2字节&#xff0c;范围是0到65535.如…

redis功能点

一、redis简介 概述 Redis 是速度非常快的非关系型&#xff08;NoSQL&#xff09;内存键值数据库&#xff0c;可以存储键和五种不同类型的值之间的映射。键的类型只能为字符串&#xff0c;值支持五种数据类型&#xff1a;字符串、列表、集合、散列表、有序集合。 Redis 支持很…

windows端给python重命名,快速将默认的python修改为 python3

问题点 在windows上&#xff0c;我们实际已经安装了python&#xff0c;但默认的是 python, 可能有的程序执行需要用到 python3&#xff0c;下面的方法可以快速将默认的python修改为 python3 解决方法 此方法需要保证windows上已经安装了python 1&#xff1a;首先找到系统的…

LED显示屏视频播放器的8大功能

随着中国LED显示屏企业的规模发展和产品技术的不断创新&#xff0c;LED显示屏在各个领域中的应用得到了广泛推广。然而&#xff0c;LED显示屏的出色表现离不开LED视频播放器这一关键设备的支持。下面将介绍LED视频播放器的8大功能&#xff0c;以及它们如何提升LED显示屏的显像效…

FPGA - AXI4_Lite(实现用户端与axi4_lite之间的交互逻辑)

在之前的博客中对AXI4总线进行了介绍&#xff08;FPGA-AXI4接口协议概述&#xff09;&#xff0c;在这篇博客中&#xff0c;实现用户端与axi4_lite之间的交互逻辑。 一&#xff0c; AXI4 1.1 AXI4 介绍 对AXI4总线简单介绍&#xff08;具体可见FPGA-AXI4接口协议概述&#…

(done) 机器学习中的方差 variance 和 偏差 bias 怎么理解?

来源&#xff1a;https://blog.csdn.net/weixin_41479678/article/details/116230631 情况1属于&#xff1a;低 bias&#xff0c;高 variance (和 human performance 相近&#xff0c;但和 验证集dev set 相远) 通常意味着模型训练轮数太多 情况2属于&#xff1a;高 bias&#…

微服务高级篇(三):分布式缓存+Redis集群

文章目录 一、单点Redis的问题及解决方案二、Redis持久化2.1 单机安装Redis2.2 RDB持久化2.3 AOF持久化2.4 RDB和AOF对比 三、Redis主从3.1 搭建Redis主从架构3.1.1 集群结构3.1.2 准备实例和配置3.1.3 启动3.1.4 开启主从关系3.1.5 测试 3.2 数据同步3.2.1 全量同步【建立连接…

【Web应用技术基础】HTML(5)——案例1:展示简历信息

样式&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>展示简历信息…

真机笔记(1)第一阶段知识讲解

目录 第一阶段讲解&#xff1a; 1.1 机房 1.2 分类&#xff1a; 1.3 机房建设标准 1.3.1 安全性: 1.3.2 供电&#xff1a; 1.3.3 空气调节&#xff1a;&#xff08;恒温恒湿&#xff09; 1.3.4 电磁防护&#xff1a; 2.1 机柜 2.2 分类 2.3 机柜的高度单位 3.1 设备…

【教程】PLSQL查看表属性乱码解决方法

一、前言 PL/SQL是Oracle数据库的编程语言&#xff0c;用于编写存储过程、触发器、函数等。 今天用plsql想查看表的属性&#xff0c;看看各个字段的注释&#xff0c;可是打开一看&#xff0c;居然是乱码的&#xff0c;如下面这样 如果在使用PL/SQL查看表属性时出现乱码&…

隐语笔记3 —— 隐语架构

隐语架构一览 隐语产品层 定位&#xff1a; 通过可视化产品&#xff0c;降低终端用户的体验和演示成本。通过模块化API降低技术集成商的研发成本。 人群画像&#xff1a; 隐私保护计算集成商&#xff0c;产品人员&#xff0c;隐私保护计算需求方&#xff0c;开发人员&#xff…