Control concis al executării cu if let
Sintaxa if let
îți oferă posibilitatea de a combina if
și let
pentru a manipula, într-un mod mai concis, valorile care corespund unui anumit șablon, ignorând în același timp restul. Ia în considerare programul din Listarea 6-6, care creează o potrivire pentru o valoare Option<u8>
în variabila config_max
, dar care intenționează să execute codul doar dacă valoarea este variantă Some
.
fn main() { let config_max = Some(3u8); match config_max { Some(max) => println!("The maximum is configured to be {}", max), _ => (), } }
Dacă valoarea este Some
, afișăm valoarea din variantă Some
prin asocierea acesteia cu variabila max
în șablon. Nu dorim să facem nimic cu valoarea None
. Pentru a respecta cerințele expresiei match
, suntem obligați să adăugăm _ => ()
după procesarea unei singure variante, ceea ce des reprezintă un cod suplimentar, inutil și iritant.
În loc să abordăm problema în modul complicat, putem simplifica procesul folosind if let
. Următorul fragment de cod funcționează identic cu instrucțiunea match
prezentată în Listarea 6-6:
fn main() { let config_max = Some(3u8); if let Some(max) = config_max { println!("The maximum is configured to be {}", max); } }
Sintaxa if let
preia un șablon și o expresie, separate de un semn de egalitate. Funcționează în mod similar cu match
, unde expresia este atribuită instrucțiunii match
, iar șablonul constituie prima sa ramură. În acest caz, șablonul este Some(max)
, iar max
se leagă de valoarea din interiorul Some
. Apoi, putem utiliza max
în corpul blocului if let
, la fel cum am folosit max
în ramura corespunzătoare a instrucțiunii match
. Codul din blocul if let
nu se execută dacă valoarea nu corespunde șablonului.
Folosind if let
, vor rezulta mai puține caractere introduse, mai puțină indentare și mai puțin cod redundant. Totuși, pierdem verificarea completă pe care instrucțiunea match
o asigură. Alegerea între match
și if let
depinde de natura situației cu care te confrunți și dacă economisirea spațiului este un compromis acceptabil pentru a nu realiza o verificare exhaustivă.
Cu alte cuvinte, poți percepe if let
drept un zahăr sintactic pentru un match
care rulează codul atunci când valoarea corespunde cu un anumit șablon, ignorând toate celelalte valori.
Avem posibilitatea de a include un else
în structura if let
. Blocul de cod alăturat lui else
este identic cu cel care ar apărea în cazul _
în expresia match
, expresie care este echivalentă cu structura if let
și else
. Acum să-ți reamintim de definiția enumerării Coin
din listarea 6-4, unde varianta Quarter
deține, de asemenea, o valoare UsState
. Dacă vom dori să numărăm toate monedele care nu sunt de tipul quarter, dar și să anunțăm starea acestora, putem realiza acest lucru cu ajutorul unei expresii match
, astfel:
#[derive(Debug)] enum UsState { Alabama, Alaska, // --snip-- } enum Coin { Penny, Nickel, Dime, Quarter(UsState), } fn main() { let coin = Coin::Penny; let mut count = 0; match coin { Coin::Quarter(state) => println!("State quarter from {:?}!", state), _ => count += 1, } }
Sau am putea folosi o expresie if let
și else
, în felul următor:
#[derive(Debug)] enum UsState { Alabama, Alaska, // --snip-- } enum Coin { Penny, Nickel, Dime, Quarter(UsState), } fn main() { let coin = Coin::Penny; let mut count = 0; if let Coin::Quarter(state) = coin { println!("State quarter from {:?}!", state); } else { count += 1; } }
Dacă te afli în situația în care logica din programul tău este prea complexă pentru a fi exprimată folosind un match
, nu uita că if let
este și el un instrument util în limbajul Rust.
Sumar
Am tratat felul în care putem folosi enumerările pentru a crea tipuri personalizate care pot avea una dintre o mulțime de valori enumerate. Am evidențiat felul în care tipul Option<T>
din biblioteca standard ne ajută a preveni erorile prin folosirea sistemului de tipuri. Atunci când valorile enumerărilor conțin date, putem utiliza match
sau if let
pentru a extrage și folosi acele valori, în funcție de numărul de cazuri pe care trebuie să le gestionăm.
Acum, programele tale Rust sunt capabile să exprime conceptele specifice domeniului tău folosind structuri și enumerări. Crearea de tipuri personalizate pentru utilizare în API-ul tău garantează securitatea tipurilor: compilatorul se va asigura că funcțiile tale primesc doar valori ale tipului așteptat de fiecare funcție.
Cu scopul de a oferi utilizatorilor tăi un API bine structurat, ușor de utilizat și care expune doar ceea ce aceștia realmente necesită, să ne focusăm acum pe modulele din Rust.