Az előző bejegyzésben a rust hibakezeléséről volt szó,
ehhez szorosan kapcsolódik az úgynevezett sentinel értékek kezelése a nyelvben. Amikor először hallottam róla, hogy a
rust-ban tulajdonképpen nincsen null
, azért egy kicsit felvontam a szemöldökömet.
Mik azok a sentinel értékek? Link to heading
A sentinel értékeket jellemzően egy adatfolyam végének megjelölésére vagy speciális állapotok jelzésére használjuk egy
programban. Ilyen például a null
esetenként a -1
vagy a NaN
. A programok gyakori hibaforrása, ha a fejlesztő
elmulasztja ezeknek az állapotoknak a kezelését, ezért a Rust nyelvben gyakorlatilag teljesen száműzték őket.
Nézzük egy kicsit hanyagul megírt Javascript programot, aminek az a feladata, hogy alakítsa át a felhasználótól kapott bemeneti érték első karakterét nagybetűre.
1function getFirstCharacterInUppercase(str) {
2 return str[0].toUpperCase() + str.slice(1);
3}
4
5const userInput = null;
6
7console.log(getFirstCharacterInUppercase(userInput)); // Output: TypeError: can't access property "toUpperCase" of null
Ezt a kódot, bár hiányzik belőle a hibakezelés probléma nélkül el lehetne juttatni egy éles környezetbe, ahol a felhasználó fogja észrevenni a hiányosságokat, ami közel sem optimális. A felhasználó miután felhívta a fejlesztő figyelmét a problémára valószínűleg a következő módon kerül javításra a kis program:
1function getFirstCharacterInUppercase(str) {
2 if (typeof str !== 'string' || str.length === 0) {
3 return '';
4 }
5 return str[0].toUpperCase() + str.slice(1);
6}
7
8const userInput = null;
9
10console.log(getFirstCharacterInUppercase(userInput)); // Output: ''
A rust a fejlett típus rendszerével segít elkerülni azt a részt, amikor a felhasználónak kell jeleznie a fejlesztőnek, hogy kifelejtette a sentinel értékek kezelését. Nézzük két rust-os változatot a korábbi Javascript függvényünkre:
1fn get_first_char_in_uppercase1(input: Option<&str>) -> String {
2 match input {
3 Some(s) if !s.is_empty() => {
4 let mut chars = s.chars();
5 match chars.next() {
6 Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
7 None => "".to_string(),
8 }
9 }
10 _ => "".to_string(),
11 }
12}
13
14fn get_first_char_in_uppercase2(input: &str) -> String {
15 let mut chars = input.chars();
16 match chars.next() {
17 Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
18 None => "".to_string(),
19 }
20}
21
22fn main() {
23 let user_input1: &str = "hello";
24
25 println!("{}", get_first_char_in_uppercase1(user_input1)); // nem fog lefordulni a program, mert nem Option paraméterrel hívtam meg a függvényt
26
27 println!("{}", get_first_char_in_uppercase2(user_input1)); // Output: 'Hello'
28
29 let user_input2: Option<String> = None;
30
31 println!("{}", get_first_char_in_uppercase1(user_input2)); // Output: ''
32
33 println!("{}", get_first_char_in_uppercase2(user_input2)); // nem fog lefordulni a program, mert nem &str paraméterrel hívtam meg a függvényt
34}
Persze, ha mindenképpen szeretnék futni egy hibajelentős kört a felhasználóval, akkor erre is van lehetőség a rust
nyelvben is, csak külön jeleznem kell a kódban .unwrap()
-al:
1// ...
2fn main() {
3 let user_input2: Option<String> = None;
4
5 println!("{}", get_first_char_in_uppercase2(user_input2.unwrap())); // le fog fordulni a program és futásidőben fog hibát dobni a felhasználónak
6}
Lásd még: Option