Operator znaku zapytania „?”
Część sekcji Logika i przepływ programu ścieżki Rust w Coddy. Lekcja 46 z 66.
Podczas pracy z funkcjami, które zwracają Result, często trzeba obsługiwać błędy, zajmując się nimi lokalnie lub przekazując je do funkcji wywołującej. Rust udostępnia elegancki operator do tego typowego wzorca: operator znaku zapytania ?.
Operator ? zapewnia przejrzysty sposób propagowania błędów bez pisania rozwlekłych instrukcji match. Gdy umieścisz ? po wartości typu Result, automatycznie wyodrębni wartość Ok lub natychmiast zwróci wartość z wariantem Err z bieżącej funkcji:
fn parse_and_double(s: &str) -> Result<i32, std::num::ParseIntError> {
let number = s.parse::<i32>()?; // Jeśli parsowanie się nie powiedzie, zwróć błąd
Ok(number * 2) // Jeśli się powiedzie, podwój liczbę
}Jest to równoważne zapisaniu pełnej instrukcji match, ale znacznie zwięźlejsze. Jeśli s.parse::<i32>() zwróci Ok, operator ? wyodrębnia wartość i przypisuje ją do number. Jeśli zwróci Err, operator ? natychmiast zwraca ten błąd z całej funkcji.
Zwróć uwagę na składnię ::<i32>. Nazywa się ją turbofish i informuje Rust, na jaki typ należy sparsować ciąg znaków. Funkcja zwraca Result<i32, std::num::ParseIntError>, gdzie i32 jest typem wyniku w przypadku powodzenia, a std::num::ParseIntError jest typem błędu zwracanym, gdy parsowanie się nie powiedzie.
Operatora ? można używać tylko w funkcjach, które zwracają Result (lub Option), ponieważ musi on mieć możliwość zwrócenia błędu.
Wyzwanie
ŁatwyOtrzymasz dwa wejścia. Pierwsze wejście to łańcuch, który należy sparsować jako liczbę całkowitą, a drugie wejście to kolejny łańcuch, który również należy sparsować jako liczbę całkowitą. Utwórz funkcję o nazwie add_numbers, która przyjmuje dwa wycinki łańcuchów jako parametry i zwraca wartość typu Result<i32, std::num::ParseIntError>. Wewnątrz funkcji użyj operatora ?, aby sparsować oba łańcuchy, i zwróć ich sumę opakowaną w Ok. Wywołaj funkcję z dwoma wejściami i obsłuż wynik za pomocą match.
Wymagania:
- Odczytaj pierwsze wejście (pierwszą liczbę jako łańcuch) i usuń białe znaki
- Odczytaj drugie wejście (drugą liczbę jako łańcuch) i usuń białe znaki
- Utwórz funkcję
add_numbers, która przyjmuje dwa parametry typu&stri zwraca wartość typuResult<i32, std::num::ParseIntError> - Wewnątrz funkcji sparsuj pierwszy łańcuch do typu
i32, używając operatora? - Sparsuj drugi łańcuch do typu
i32, używając operatora? - Zwróć
Ok(sum), gdzie sumą jest dodanie obu sparsowanych liczb - Wywołaj funkcję z dwoma łańcuchami wejściowymi
- Użyj wyrażenia
match, aby obsłużyć wartość typuResult - W ramieniu
Ok(value)wypisz:Sum: [value] - W ramieniu
Err(_)wypisz:Parsing error
Wejście:
- Pierwszy wiersz: łańcuch reprezentujący liczbę (np.
15) - Drugi wiersz: łańcuch reprezentujący inną liczbę (np.
27)
Wyjście:
- Jeśli oba łańcuchy są prawidłowymi liczbami:
Sum: [result] - Jeśli nie można sparsować któregoś z łańcuchów:
Parsing error
Spróbuj swoich sił
use std::io;
// TODO: Utwórz tutaj funkcję add_numbers
// Powinna przyjmować dwa parametry &str i zwracać Result<i32, std::num::ParseIntError>
fn main() {
// Wczytaj pierwszą wartość wejściową
let mut input1 = String::new();
io::stdin().read_line(&mut input1).expect("Failed to read line");
let input1 = input1.trim();
// Wczytaj drugą wartość wejściową
let mut input2 = String::new();
io::stdin().read_line(&mut input2).expect("Failed to read line");
let input2 = input2.trim();
// TODO: Wywołaj add_numbers z input1 i input2
// TODO: Użyj match do obsługi Result
// Wypisz "Sum: [value]" dla Ok(value)
// Wypisz "Parsing error" dla Err(_)
}Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Logika i przepływ programu
1Zaawansowane sterowanie przepływem
Wyrażenie „match”Dopasowywanie wielu wartościDopasowywanie zakresówWyrażenie „if let”Pętle jako wyrażeniaPodsumowanie — prosty parser poleceń4Grupowanie danych za pomocą struktur
Czym jest struktura?Przegląd strukturDostęp do pól strukturyModyfikowalne strukturyStruktury jako parametry funkcjiStruktury krotkowePodsumowanie — utwórz strukturę Book7Obsługa błędów za pomocą „Result”
Czym jest „Result”?Używanie „match” z „Result”is_ok() i is_err()Skróty: unwrap i expectOperator znaku zapytania „?”Konwertowanie ciągów znaków na liczbyPodsumowanie — bezpieczna funkcja dzielenia2Wprowadzenie do wektorów
Czym jest wektor?Tworzenie wektoraDodawanie elementów za pomocą pushDostęp do elementów wektoraIterowanie po wektorzeIterowanie z możliwością modyfikacjiUsuwanie elementówPodsumowanie — prosty licznik punktów5Pary klucz–wartość z mapami hashującymi
Czym jest mapa haszująca?Tworzenie mapy haszującejWstawianie par klucz–wartośćDostęp do wartościIterowanie po mapie haszującejAktualizowanie wartościUsuwanie paryPodsumowanie – licznik słów8Projekt: Prosty system inwentaryzacji
Konfiguracja projektuDodawanie produktuSprawdzanie stanu magazynowegoSprzedaż produktuŁączenie wszystkiego w całość3Lista zadań w wierszu poleceń
Konfiguracja projektuDodawanie zadaniaWyświetlanie wszystkich zadańUsuwanie zadaniaKońcowy kodPoćwicz samodzielnie: Kompilator Rust online