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函数几乎相同。唯一的区别是我们将query和line都小写,因此无论输入参数的大小写如何,当我们检查该行是否包含查询时,它们都是相同的大小写。
文件名: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”:该字符串片段不包含供我们使用的小写u或t,因此我们必须分配一个包含“rust”的新String。当我们现在将query作为参数传递给contains方法时,我们需要添加一个&符号,因为contains的签名被定义为接受一个字符串切片。
接下来,我们在line添加一个对to_lowercase的调用,以小写所有字符。现在我们已经将line和query转换为小写,无论查询的大小写如何,我们都将找到匹配项。
让我们看看这个实现是否通过了测试:
$ 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中的值调用search或search_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,而不是使用unwrap、expect或我们在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函数的实现思路
- 通过添加环境变量的方式实现
相关文章:

Rust之构建命令行程序(五):环境变量
开发环境 Windows 11Rust 1.77.0 VS Code 1.87.2 项目工程 这次创建了新的工程minigrep. 使用环境变量 我们将通过添加一个额外的功能来改进minigrep:一个不区分大小写的搜索选项,用户可以通过环境变量打开该选项。我们可以将此功能设置为命令行选项,…...

ARMday7
VID_20240322_203313 1.思维导图 2.main.c #include"key_inc.h" //封装延时函数 void delay(int ms) {int i,j;for(i0;i<ms;i){for(j0;j<2000;j){}} } int main() {//按键中断的初始化key1_it_config();key2_it_config();key3_it_config();while(1){printf(&q…...
Ubuntu中安装VSCode的一个指令
问题描述 本来想去VSCode官网上下载软件包,然后双击使用Ubuntu Software安装的,但是安装老不成功。 想用命令行指令dpkg进行安装,虽然能成功,但是后续使用 code . 命令打开VSCode又报错说找不到命令。 解决方式 在命令行中使用…...
生活电子产品拆解分析~汇总目录
一、锂电池电源 ①电子产品拆解分析-暖手宝 ②电子产品拆解分析-电动牙刷 ③电子产品拆解分析-充电宝台灯 ④电子产品拆解分析-太阳能自动感应灯 ⑤电子产品拆解分析-人体感应灯 ⑥电子产品拆解分析-食物电子秤 ⑦电子产品拆解分析-6600mA充电宝 ⑨电子产品拆解分析-触摸化妆镜…...

Tkinter 一文读懂
Tkinter 简介 Tkinter(即 tk interface,简称“Tk”)本质上是对 Tcl/Tk 软件包的 Python 接口封装,它是 Python 官方推荐的 GUI 工具包,属于 Python 自带的标准库模块,当您安装好 Python 后,就可…...

2核4G服务器阿里云性能测评和优惠价格表
阿里云2核4G服务器租用优惠价格,轻量2核4G服务器165元一年、u1服务器2核4G5M带宽199元一年、云服务器e实例30元3个月,活动链接 aliyunfuwuqi.com/go/aliyun 活动链接如下图: 阿里云2核4G服务器优惠价格 轻量应用服务器2核2G4M带宽、60GB高效…...

Day41:WEB攻防-ASP应用HTTP.SYS短文件文件解析Access注入数据库泄漏
目录 ASP-默认安装-MDB数据库泄漏下载 ASP-中间件-CVE&短文件&解析&写权限 HTTP.SYS(CVE-2015-1635)主要用作蓝屏破坏,跟权限不挂钩 IIS短文件(iis全版本都可能有这个问题) IIS文件解析 IIS写权限 ASP-SQL注入-SQLMAP使用…...

什么是单点登录?
单点登录(Single Sign On,简称 SSO)简单来说就是用户只需在一处登录,不用在其他多系统环境下重复登录。用户的一次登录就能得到其他所有系统的信任。 为什么需要单点登录 单点登录在大型网站应用频繁,比如阿里旗下有淘…...

elasticsearch的数据搜索
DSL查询文档 elasticsearch的查询依然是基于JSON风格的DSL来实现的。 Elasticsearch提供了基于JSON的DSL(Domain Specific Language)来定义查询。常见的查询类型包括: 查询所有:查询出所有数据,一般测试用。例如:match_all 全文检索(full text)查询:利用分词器对用户…...
云原生相关概念(小白版)
先说概念: 云原生应该是一种“建立在云上的多种效率提升技术的复合体"(而不是单一的技术创新),主要就是在云技术摆脱物理储存限制的基础上,进一步实现应用的专业优化(即文章里说的按功能切分…...

Dell戴尔XPS 12 9250二合一笔记本电脑原装出厂Windows10系统包下载
链接:https://pan.baidu.com/s/1rqUEM_q5DznF0om6eevcwg?pwdvij0 提取码:vij0 戴尔原厂WIN10系统自带所有驱动、出厂主题壁纸、系统属性专属联机支持标志、系统属性专属LOGO标志、Office办公软件、MyDell等预装程序 文件格式:esd/wim/sw…...

YOLOv5改进 | 图像去雾 | 利用图像去雾网络AOD-PONO-Net网络增改进图像物体检测(全网独家首发)
一、本文介绍 本文给大家带来的改进机制是利用AODNet图像去雾网络结合PONO机制实现二次增强,我将该网络结合YOLOv5针对图像进行去雾检测(也适用于一些模糊场景,图片不清晰的检测),同时本文的内容不影响其它的模块改进可以作为工作量凑近大家的论文里,非常的适用,图像去…...

代码随想录算法训练营Day55 ||leetCode 583. 两个字符串的删除操作 || 72. 编辑距离
583. 两个字符串的删除操作 这道题的状态方程比上一题简单一些 初始化如下 class Solution { public:int minDistance(string word1, string word2) {vector<vector<int>> dp(word1.size() 1, vector<int>(word2.size() 1));for (int i 0; i < word1…...
Hive常用函数 之 数值处理
Hive常用函数 之 数值处理 以下是Hive中常用的数值处理函数,可用于执行各种数学运算和数值转换操作。 1. ABS():返回一个数的绝对值。 SELECT ABS(-10); -- 输出: 102. ROUND():对一个数进行四舍五入。 SELECT ROUND(10.56); -- 输出: 113.…...
策略模式在项目中实际应用
Java策略模式是一种行为设计模式,它使你能在运行时改变对象的行为。策略模式定义了一系列的算法,并将每一个算法封装起来,使它们可以互相替换。策略模式使得算法可以独立于使用它的客户端变化。在Java中实现策略模式,通常包含三个…...

没有磁盘整列下的多机分布式存储:使用rysnc+多服务器文件/文件夹内容同步
目录 0.为什么要定时同步 1.程序安装 2.文件夹设置rsync使用 3.使用cron进行定时任务 0.为什么要定时同步 作为科研党,实验室有多个服务器,但是都是分批买的没有上磁盘整列,所以一个服务器上跑的东西并不能同步,有时候挂任务要…...

SQL:窗口函数之OVER()
窗口函数 通用格式 “函数 OVER (PARTITION BY 分组 ORDER BY 排序依据 升降序)”。 这里记录下OVER() 以及搭配LEAD/LAG函数的使用方法(执行平台Impala) 目录 OVER函数1、不加条件的OVER函数——得到所有的汇总结果2、仅有排序的OVER函数——得到按顺序…...

嵌入式开发--STM32G431RBTx-定时器中断流水灯
嵌入式开发–STM32G431RBTx-定时器中断流水灯 定时器工作原理 如图有反映stm32g431的定时器资源。 共10个定时器 定时器定时器类型个数TIM6,7基本定时器2TIM2,3,4全功能通用定时器3TIM15,16,17通用定时器(只有1或2个…...

人像抠图HumanSeg——基于大规模电话会议视频数据集的连接感知人像分割
前言 人像抠图将图像中的人物与背景进行像素级别的区分的技术。通过人像分割,可以实现诸如背景虚化、弹幕穿人等各种有趣的功能,为视频通话和影音观看提供更加优质和丰富的体验。由于广泛部署到Web、手机和边缘设备,肖像分割在兼顾分割精度的…...

Qt 项目使用visual studio 进行开发调试
https://marketplace.visualstudio.com/items?itemNameTheQtCompany.QtVisualStudioTools2015 https://devblogs.microsoft.com/cppblog/bring-your-existing-qt-projects-to-visual-studio/ 正常Qt开发中,使用Qt Creator 进行windows下MSVC编译器的调试是一件挺麻…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...

PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...

人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...