Step 1: Write a failed test
We follow the Test Driven Development (TDD) approach and start by writing a test to verify case-insensitive search functionality. Since we haven't implemented this feature yet, this test will fail.
Here is the test code:
#[cfg(test)] mod tests { use super::*; // Test: case sensitive search #[test] fn case_sensitive() { let query = "duct"; let contents = "\ Rust: safe, fast, productive. Pick three. Duct tape."; // I hope to return case-sensitive matching results assert_eq!(vec!["safe, fast, productive."], search(query, contents)); } // Test: Case-insensitive search #[test] fn case_insensitive() { let query = "rUsT"; // The query string is inconsistent in case let contents = "\ Rust: safe, fast, productive. Pick three. Trust me."; // Important to return case-insensitive matching results assert_eq!( vec!["Rust:", "Trust me."], search_case_insensitive(query, contents) ); } }
In the above code:
-
case_sensitive
The test verified the original case-sensitive search. -
case_insensitive
The test verifies the case-insensitive search we will implement later. At this time, since we have not achieved it yetsearch_case_insensitive
Function, compilation will fail.
Step 2: Implement the search_case_insensitive function
In order to achieve case-insensitive search, we need to modifysearch
function, enabling it to ignore case.
The following issearch_case_insensitive
Function implementation:
// Case-insensitive search functionpub fn search_case_insensitive<'a>( query: &str, // Query string contents: &'a str, // File content) -> Vec<&'a str> { let query = query.to_lowercase(); // Convert query string to lowercase let mut results = Vec::new(); //Storing matching results // Iterate through every line in the file for line in () { // Convert each line to lowercase and compare if line.to_lowercase().contains(&query) { (line); // If it matches, add to the result list } } results // Return the matching row}
Code explanation:
-
query.to_lowercase()
Convert query strings to lowercase to ensure that matches are case-insensitive. -
line.to_lowercase()
Convert each line to lowercase and check if the query string is included.
Step 3: Modify the run function
run
Functions are the core of the program, which is responsible for performing searches and outputting results. We need to modifyrun
function, make it according toConfig
In the structureignore_case
The fields are case sensitivesearch
Functions are case-insensitivesearch_case_insensitive
function.
// Run the search according to the configurationpub fn run(config: Config) -> Result<(), Box<dyn Error>> { let contents = fs::read_to_string(config.file_path)?; // Read file content // Decide which search to use based on the ignore_case field let results = if config.ignore_case { search_case_insensitive(&, &contents) // Case-insensitive search } else { search(&, &contents) // Case sensitive search }; // Print the matching line for line in results { println!("{line}"); } Ok(()) }
Code explanation:
-
Config
The structure contains aignore_case
Fields that control whether to enable case-insensitive search. - according to
ignore_case
We decide to call the value ofsearch
stillsearch_case_insensitive
。
Step 4: Get environment variables
Now we need to get it from the environment variableIGNORE_CASE
The value of , to determine whether to enable case-insensitive search.
We use the Rust standard libraryenv
module to access environment variables.
use std::env; impl Config { // Build a Config instance pub fn build(args: &[String]) -> Result<Config, &'static str> { if () < 3 { return Err("not enough arguments"); } let query = args[1].clone(); let file_path = args[2].clone(); // Check whether the environment variable IGNORE_CASE is set let ignore_case = env::var("IGNORE_CASE").is_ok(); // If the environment variable exists, then case-insensitive search is enabled Ok(Config { query, file_path, ignore_case, }) } }
Code explanation:
- We use
env::var("IGNORE_CASE").is_ok()
Check environment variablesIGNORE_CASE
Whether it is set. - If this environment variable is set, we will
ignore_case
Set astrue
, otherwise the default isfalse
。
Step 5: Run the program
Now, our program has supported controlling search patterns based on environment variables. You can run the program with the following command:
- Perform case-sensitive searches without using environment variables:
$ cargo run -- to
-
Set environment variables
IGNORE_CASE=1
, enable case-insensitive search:
$ IGNORE_CASE=1 cargo run -- to
For PowerShell users, you can use the following command:
PS> $Env:IGNORE_CASE=1; cargo run -- to
Summarize
By using environment variables, we successfully implemented case-insensitive search function in the Rust program.
This method allows users to change the behavior of programs through simple environment variable configurations without specifying command line parameters every time the program is run.
Through this method, we can flexibly control different search modes in command line tools, making the program more friendly and easy to configure.
In this tutorial, we:
- Failed tests were written through TDD and the functionality was implemented step by step.
- Learn how to use the Rust standard library
env
The module gets environment variables. - Control program behavior through environment variables, making command-line tools more flexible.
With this example, I hope you have some understanding of how to use environment variables in Rust and can apply them flexibly in your own project.
The above is personal experience. I hope you can give you a reference and I hope you can support me more.