Shopping cart

0

Cart

  • 0 item

Nessun prodotto nel carrello.

All categories
 Corso Gratuito di Programmazione Rust Lezione 044 – Lavorare con le variabili d’ambiente

SE VUOI PRENDERE LA CERTIFICAZIONE PER QUESTO CORSO CLICCA QUI

Corso su Lavorare con le Variabili d’Ambiente

Aggiungeremo una funzionalità extra a minigrep: un’opzione per la ricerca insensibile alle maiuscole e minuscole che l’utente può attivare tramite una variabile d’ambiente. Potremmo rendere questa funzionalità un’opzione da riga di comando e richiedere agli utenti di inserirla ogni volta che vogliono che si applichi, ma facendo invece di renderla una variabile d’ambiente, permettiamo ai nostri utenti di impostare la variabile d’ambiente una volta e avere tutte le loro ricerche insensibili alle maiuscole e minuscole in quella sessione terminale.

Scrittura di un Test Fallimentare per la Funzione di Ricerca Insensibile alle Maiuscole e Minuscole

Inizieremo aggiungendo una nuova funzione search_case_insensitive che verrà chiamata quando la variabile d’ambiente ha un valore. Continueremo a seguire il processo TDD, quindi il primo passo è di nuovo scrivere un test fallimentare. Aggiungeremo un nuovo test per la nuova funzione search_case_insensitive e rinomineremo il nostro vecchio test da one_result a case_sensitive per chiarire le differenze tra i due test.

rust

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)
);
}
}

Il nuovo test per la ricerca insensibile alle maiuscole e minuscole usa “rUsT” come sua query. Nella funzione search_case_insensitive che stiamo per aggiungere, la query “rUsT” dovrebbe corrispondere alla riga contenente “Rust:” con una R maiuscola e corrispondere alla riga “Trust me.” anche se entrambe hanno una diversa maiuscola e minuscola dalla query. Questo è il nostro test fallimentare e non compilerà perché non abbiamo ancora definito la funzione search_case_insensitive.

Implementazione della Funzione search_case_insensitive

La funzione search_case_insensitive, mostrata qui di seguito, sarà quasi identica alla funzione search. L’unica differenza è che convertiremo in minuscolo la query e ogni riga così che qualunque sia la combinazione delle lettere maiuscole e minuscole negli argomenti di input, avranno la stessa combinazione di lettere quando controlliamo se la riga contiene la query.

rust

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
}

Prima, convertiamo la stringa di query in minuscolo e la salviamo in una variabile ombreggiata con lo stesso nome. Chiamare to_lowercase sulla query è necessario in modo che indipendentemente dalla query dell’utente sia “rust”, “RUST”, “Rust” o “rUsT”, tratteremo la query come se fosse “rust” e saremo insensibili alle maiuscole e minuscole. Mentre to_lowercase gestirà l’Unicode di base, non sarà al 100% accurato. Se stessimo scrivendo un’applicazione reale, vorremmo fare un po’ di lavoro in più qui, ma questa sezione tratta di variabili d’ambiente, non di Unicode, quindi lo lasceremo così qui.

Osserva che query è ora una String anziché un riferimento a stringa, perché chiamando to_lowercase si creano nuovi dati anziché fare riferimento a dati esistenti. Diciamo che la query è “rUsT”, come esempio: quella stringa di riferimento non contiene una u o t in minuscolo per noi da usare, quindi dobbiamo allocare una nuova String contenente “rust”. Quando passiamo query come argomento al metodo contains ora, dobbiamo aggiungere un simbolo & perché la firma di contains è definita per prendere un riferimento a stringa.

Successivamente, aggiungiamo una chiamata a to_lowercase su ogni riga per convertire in minuscolo tutte le lettere. Ora che abbiamo convertito line e query in minuscolo, troveremo corrispondenze non importa quale sia la combinazione di maiuscole e minuscole della query.

Vediamo se questa implementazione supera i test:

rust

$ cargo test
Compiling minigrep v0.1.0 (file:///projects/minigrep)
Finished test [unoptimized + debuginfo] target(s) in 1.33s
Running unittests src/lib.rs (target/debug/deps/minigrep-9cd200e5fac0fc94)
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; finished in 0.00s

Ottimo! Sono passati. Ora, chiamiamo la nuova funzione search_case_insensitive dalla funzione run. Innanzitutto, aggiungeremo un’opzione di configurazione alla struttura Config per passare dalla ricerca sensibile alle maiuscole e minuscole alla ricerca insensibile alle maiuscole e minuscole. Aggiungere questo campo causerà errori del compilatore perché non stiamo ancora inizializzando questo campo da nessuna parte:

rust

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

Abbiamo aggiunto il campo ignore_case che contiene un booleano. Successivamente, abbiamo bisogno che la funzione run verifichi il valore del campo ignore_case e utilizzi quello per decidere se chiamare la funzione search_case_insensitive o search.

rust

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(())
}

Infine, dobbiamo controllare la variabile d’ambiente. Le funzioni per lavorare con le variabili d’ambiente sono nel modulo env nella libreria standard, quindi portiamo quel modulo nello scope all’inizio di src/lib.rs. Poi useremo la funzione var dal modulo env per controllare se è stato impostato un valore per una variabile d’ambiente chiamata IGNORE_CASE.

rust

use std::env; 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,
})
}
}

Qui, creiamo una nuova variabile ignore_case. Per impostare il suo valore, chiamiamo la funzione env::var e passiamo il nome della variabile d’ambiente IGNORE_CASE. La funzione env::var restituisce un Result che sarà il risultato Ok se contiene il valore della variabile d’ambiente se la variabile d’ambiente è impostata con un valore. Restituirà il risultato Err se la variabile d’ambiente non è impostata.

Usiamo il metodo is_ok sul Result per controllare se la variabile d’ambiente è impostata, il che significa che il programma dovrebbe fare una ricerca insensibile alle maiuscole e minuscole. Se la variabile d’ambiente IGNORE_CASE non è impostata su niente, is_ok restituirà false e il programma eseguirà una ricerca sensibile alle maiuscole e minuscole. Non ci interessa il valore della variabile d’ambiente, solo se è impostata o meno, quindi controlliamo is_ok anziché utilizzare unwrap, expect, o qualsiasi altro metodo su Result.

Passiamo il valore nella variabile ignore_case all’istanza di Config in modo che la funzione run possa leggere quel valore e decidere se chiamare search_case_insensitive o search.

Proviamo! Prima, eseguiamo il nostro programma senza impostare la variabile d’ambiente e con la query to, che dovrebbe corrispondere a qualsiasi riga che contiene la parola “to” in minuscolo:

rust

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

Sembra che funzioni ancora! Ora, eseguiamo il programma con IGNORE_CASE impostato su 1 ma con la stessa query to.

rust

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

Se stai usando PowerShell, dovrai impostare la variabile d’ambiente ed eseguire il programma come comandi separati:

rust

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

Ciò renderà IGNORE_CASE persistente per il resto della sessione della shell. Può essere annullato con il comando Remove-Item:

rust

PS> Remove-Item Env:IGNORE_CASE

Dovremmo ottenere righe che contengono “to” che potrebbero avere lettere maiuscole:

css

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

Eccellente, abbiamo ottenuto anche righe contenenti “To”! Il nostro programma minigrep ora può fare ricerche insensibili alle maiuscole e minuscole controllate da una variabile d’ambiente. Ora sai come gestire le opzioni impostate tramite argomenti da riga di comando o variabili d’ambiente.

Alcuni programmi consentono argomenti e variabili d’ambiente per la stessa configurazione. In quei casi, i programmi decidono che uno o l’altro ha la precedenza. Per un altro esercizio da fare da solo, prova a controllare la sensibilità alle maiuscole e minuscole tramite un argomento da riga di comando o una variabile d’ambiente. Decidi se l’argomento da riga di comando o la variabile d’ambiente dovrebbe avere la precedenza se il programma viene eseguito con uno impostato su case sensitive e uno impostato su case insensitive.

Il modulo std::env contiene molte altre funzionalità utili per gestire le variabili d’ambiente: controlla la sua documentazione per vedere cosa è disponibile.

1 Comment

Leave a Reply

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *