SoFunction
Updated on 2025-04-09

Use environment variables to implement case-insensitive search methods in Rust programs

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_sensitiveThe test verified the original case-sensitive search.
  • case_insensitiveThe test verifies the case-insensitive search we will implement later. At this time, since we have not achieved it yetsearch_case_insensitiveFunction, compilation will fail.

Step 2: Implement the search_case_insensitive function

In order to achieve case-insensitive search, we need to modifysearchfunction, enabling it to ignore case.

The following issearch_case_insensitiveFunction 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

runFunctions are the core of the program, which is responsible for performing searches and outputting results. We need to modifyrunfunction, make it according toConfigIn the structureignore_caseThe fields are case sensitivesearchFunctions are case-insensitivesearch_case_insensitivefunction.

// 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:

  • ConfigThe structure contains aignore_caseFields that control whether to enable case-insensitive search.
  • according toignore_caseWe decide to call the value ofsearchstillsearch_case_insensitive

Step 4: Get environment variables

Now we need to get it from the environment variableIGNORE_CASEThe value of , to determine whether to enable case-insensitive search.

We use the Rust standard libraryenvmodule 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 useenv::var("IGNORE_CASE").is_ok()Check environment variablesIGNORE_CASEWhether it is set.
  • If this environment variable is set, we willignore_caseSet 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:

  1. Perform case-sensitive searches without using environment variables:
$ cargo run -- to 
  1. Set environment variablesIGNORE_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 libraryenvThe 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.