处理环境变量
我们将增加一个额外的功能来改进 minigrep
:用户可以通过设置环境变量来设置搜索是否是大小写敏感的 。当然,我们也可以将其设计为一个命令行参数并要求用户每次需要时都加上它,不过在这里我们将使用环境变量。这允许用户设置环境变量一次之后在整个终端会话中所有的搜索都将是大小写不敏感的。
编写一个大小写不敏感 search
函数的失败测试
我们希望增加一个新函数 search_case_insensitive
,并将会在设置了环境变量时调用它。这里将继续遵循 TDD 过程,其第一步是再次编写一个失败测试。我们将为新的大小写不敏感搜索函数新增一个测试函数,并将老的测试函数从 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) ); } }
注意我们也改变了老测试中 contents
的值。还新增了一个含有文本 "Duct tape."
的行,它有一个大写的 D,这在大小写敏感搜索时不应该匹配 “duct”。我们修改这个测试以确保不会意外破坏已经实现的大小写敏感搜索功能;这个测试现在应该能通过并在处理大小写不敏感搜索时应该能一直通过。
大小写 不敏感 搜索的新测试使用 "rUsT"
作为其查询字符串。在我们将要增加的 search_case_insensitive
函数中,"rUsT"
查询应该包含带有一个大写 R 的 "Rust:"
还有 "Trust me."
这两行,即便他们与查询的大小写都不同。这个测试现在不能编译,因为还没有定义 search_case_insensitive
函数。请随意增加一个总是返回空 vector 的骨架实现,正如示例 12-16 中 search
函数为了使测试通过编译并失败时所做的那样。
实现 search_case_insensitive
函数
search_case_insensitive
函数,如示例 12-21 所示,将与 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 }
首先我们将 query
字符串转换为小写,并将其覆盖到同名的变量中。对查询字符串调用 to_lowercase
是必需的,这样不管用户的查询是 "rust"
、"RUST"
、"Rust"
或者 "rUsT"
,我们都将其当作 "rust"
处理并对大小写不敏感。
注意 query
现在是一个 String
而不是字符串 slice,因为调用 to_lowercase
是在创建新数据,而不是引用现有数据。如果查询字符串是 "rUsT"
,这个字符串 slice 并不包含可供我们使用的小写的 u
或 t
,所以必需分配一个包含 "rust"
的新 String
。现在当我们将 query
作为一个参数传递给 contains
方法时,需要增加一个 & 因为 contains
的签名被定义为获取一个字符串 slice。
接下来在检查每个 line
是否包含 search
之前增加了一个 to_lowercase
调用将他们都变为小写。现在我们将 line
和 query
都转换成了小写,这样就可以不管查询的大小写进行匹配了。
让我们看看这个实现能否通过测试:
running 2 tests test tests::case_insensitive ... ok test tests::case_sensitive ... ok test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
好的!现在,让我们在 run
函数中实际调用新 search_case_insensitive
函数。首先,我们将在 Config
结构体中增加一个配置项来切换大小写敏感和大小写不敏感搜索。增加这些字段会导致编译错误,因为我们还没有在任何地方初始化这些字段:
文件名: src/lib.rs
pub struct Config { pub query: String, pub filename: String, pub case_sensitive: bool, }
这里增加了 case_sensitive
字符来存放一个布尔值。接着我们需要 run
函数检查 case_sensitive
字段的值并使用它来决定是否调用 search
函数或 search_case_insensitive
函数,如示例 12-22 所示。注意这还不能编译:
文件名: src/lib.rs
# use std::error::Error; # use std::fs::{self, File}; # use std::io::prelude::*; # # pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { # vec![] # } # # pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { # vec![] # } # # pub struct Config { # query: String, # filename: String, # case_sensitive: bool, # } # pub fn run(config: Config) -> Result<(), Box<dyn Error>> { let contents = fs::read_to_string(config.filename)?; let results = if config.case_sensitive { search(&config.query, &contents) } else { search_case_insensitive(&config.query, &contents) }; for line in results { println!("{}", line); } Ok(()) }
最后需要实际检查环境变量。处理环境变量的函数位于标准库的 env
模块中,所以我们需要在 src/lib.rs 的开头增加一个 use std::env;
行将这个模块引入作用域中。接着在 Config::new
中使用 env
模块的 var
方法来检查一个叫做 CASE_INSENSITIVE
的环境变量,如示例 12-23 所示:
文件名: src/lib.rs
use std::env; # struct Config { # query: String, # filename: String, # case_sensitive: bool, # } // --snip-- impl Config { pub fn new(args: &[String]) -> Result<Config, &'static str> { if args.len() < 3 { return Err("not enough arguments"); } let query = args[1].clone(); let filename = args[2].clone(); let case_sensitive = env::var("CASE_INSENSITIVE").is_err(); Ok(Config { query, filename, case_sensitive }) } }
这里创建了一个新变量 case_sensitive
。为了设置它的值,需要调用 env::var
函数并传递我们需要寻找的环境变量名称,CASE_INSENSITIVE
。env::var
返回一个 Result
,它在环境变量被设置时返回包含其值的 Ok
成员,并在环境变量未被设置时返回 Err
成员。
我们使用 Result
的 is_err
方法来检查其是否是一个 error(也就是环境变量未被设置的情况),这也就意味着我们 需要 进行一个大小写敏感搜索。如果CASE_INSENSITIVE
环境变量被设置为任何值,is_err
会返回 false 并将进行大小写不敏感搜索。我们并不关心环境变量所设置的 值,只关心它是否被设置了,所以检查 is_err
而不是 unwrap
、expect
或任何我们已经见过的 Result
的方法。
我们将变量 case_sensitive
的值传递给 Config
实例,这样 run
函数可以读取其值并决定是否调用 search
或者示例 12-22 中实现的 search_case_insensitive
。
让我们试一试吧!首先不设置环境变量并使用查询 to
运行程序,这应该会匹配任何全小写的单词 “to” 的行:
$ cargo run to poem.txt Compiling minigrep v0.1.0 (file:///projects/minigrep) Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs Running `target/debug/minigrep to poem.txt` Are you nobody, too? How dreary to be somebody!
看起来程序仍然能够工作!现在将 CASE_INSENSITIVE
设置为 1
并仍使用相同的查询 to
。
如果你使用 PowerShell,则需要用两个命令来设置环境变量并运行程序:
$ $env:CASE_INSENSITIVE=1 $ cargo run to poem.txt
这回应该得到包含可能有大写字母的 “to” 的行:
$ CASE_INSENSITIVE=1 cargo run to poem.txt Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs Running `target/debug/minigrep to poem.txt` Are you nobody, too? How dreary to be somebody! To tell your name the livelong day To an admiring bog!
好极了,我们也得到了包含 “To” 的行!现在 minigrep
程序可以通过环境变量控制进行大小写不敏感搜索了。现在你知道了如何管理由命令行参数或环境变量设置的选项了!
一些程序允许对相同配置同时使用参数 和 环境变量。在这种情况下,程序来决定参数和环境变量的优先级。作为一个留给你的测试,尝试通过一个命令行参数或一个环境变量来控制大小写不敏感搜索。并在运行程序时遇到矛盾值时决定命令行参数和环境变量的优先级。
std::env
模块还包含了更多处理环境变量的实用功能;请查看官方文档来了解其可用的功能。
推荐几款学习编程的免费平台
免费在线开发平台(https://docs.ltpp.vip/LTPP/)
探索编程世界的新天地,为学生和开发者精心打造的编程平台,现已盛大开启!这个平台汇集了近4000道精心设计的编程题目,覆盖了C、C++、JavaScript、TypeScript、Go、Rust、PHP、Java、Ruby、Python3以及C#等众多编程语言,为您的编程学习之旅提供了一个全面而丰富的实践环境。
在这里,您不仅可以查看自己的代码记录,还能轻松地在云端保存和运行代码,让编程变得更加便捷。平台还提供了私聊和群聊功能,让您可以与同行们无障碍交流,分享文件,共同进步。不仅如此,您还可以通过阅读文章、参与问答板块和在线商店,进一步拓展您的知识边界。
为了提升您的编程技能,平台还设有每日一题、精选题单以及激动人心的编程竞赛,这些都是备考编程考试的绝佳资源。更令人兴奋的是,您还可以自定义系统UI,选择视频或图片作为背景,打造一个完全个性化的编码环境,让您的编程之旅既有趣又充满挑战。
免费公益服务器(https://docs.ltpp.vip/LTPP-SHARE/linux.html)
作为开发者或学生,您是否经常因为搭建和维护编程环境而感到头疼?现在,您不必再为此烦恼,因为一款全新的免费公共服务器已经为您解决了所有问题。这款服务器内置了多种编程语言的编程环境,并且配备了功能强大的在线版VS Code,让您可以随时随地在线编写代码,无需进行任何复杂的配置。
随时随地,云端编码
无论您身在何处,只要有网络连接,就可以通过浏览器访问这款公共服务器,开始您的编程之旅。这种云端编码的便利性,让您的学习或开发工作不再受限于特定的设备或环境。
丰富的编程语言支持
服务器支持包括C、C++、JavaScript、TypeScript、Go、Rust、PHP、Java、Ruby、Python3以及C#等在内的多种主流编程语言,满足不同开发者和学生的需求。无论您是初学者还是资深开发者,都能找到适合自己的编程环境。
在线版VS Code,高效开发
内置的在线版VS Code提供了与本地VS Code相似的编辑体验,包括代码高亮、智能提示、代码调试等功能,让您即使在云端也能享受到高效的开发体验。
数据隐私和安全提醒
虽然服务器是免费的,但为了保护您的数据隐私和安全,我们建议您不要上传任何敏感或重要的数据。这款服务器更适合用于学习和实验,而非存储重要信息。
免费公益MYSQL(https://docs.ltpp.vip/LTPP-SHARE/mysql.html)
作为一名开发者或学生,数据库环境的搭建和维护往往是一个复杂且耗时的过程。但不用担心,现在有一款免费的MySQL服务器,专为解决您的烦恼而设计,让数据库的使用变得简单而高效。
性能卓越,满足需求
虽然它是免费的,但性能绝不打折。服务器提供了稳定且高效的数据库服务,能够满足大多数开发和学习场景的需求。
在线phpMyAdmin,管理更便捷
内置的在线phpMyAdmin管理面板,提供了一个直观且功能强大的用户界面,让您可以轻松地查看、编辑和管理数据库。
数据隐私提醒,安全第一
正如您所知,这是一项公共资源,因此我们强烈建议不要上传任何敏感或重要的数据。请将此服务器仅用于学习和实验目的,以确保您的数据安全。
免费在线WEB代码编辑器(https://docs.ltpp.vip/LTPP-WEB-IDE/)
无论你是开发者还是学生,编程环境的搭建和管理可能会占用你宝贵的时间和精力。现在,有一款强大的免费在线代码编辑器,支持多种编程语言,让您可以随时随地编写和运行代码,提升编程效率,专注于创意和开发。
多语言支持,无缝切换
这款在线代码编辑器支持包括C、C++、JavaScript、TypeScript、Go、Rust、PHP、Java、Ruby、Python3以及C#在内的多种编程语言,无论您的项目需要哪种语言,都能在这里找到支持。
在线运行,快速定位问题
您可以在编写代码的同时,即时运行并查看结果,快速定位并解决问题,提高开发效率。
代码高亮与智能提示
编辑器提供代码高亮和智能提示功能,帮助您更快地编写代码,减少错误,提升编码质量。
免费二维码生成器(https://docs.ltpp.vip/LTPP-QRCODE/)
二维码(QR Code)是一种二维条码,能够存储更多信息,并且可以通过智能手机等设备快速扫描识别。它广泛应用于各种场景,如:
企业宣传
企业可以通过二维码分享公司网站、产品信息、服务介绍等。
活动推广
活动组织者可以创建二维码,参与者扫描后可以直接访问活动详情、报名链接或获取电子门票。
个人信息分享
个人可以生成包含联系方式、社交媒体链接、个人简历等信息的二维码。
电子商务
商家使用二维码进行商品追踪、促销活动、在线支付等。
教育
教师可以创建二维码,学生扫描后可以直接访问学习资料或在线课程。
交通出行
二维码用于公共交通的票务系统,乘客扫描二维码即可进出站或支付车费。 功能强大的二维码生成器通常具备用户界面友好,操作简单,即使是初学者也能快速上手和生成的二维码可以在各种设备和操作系统上扫描识别的特点。