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