Представлення ?
Іноді ми просто хочемо простоти unwrap без можливості panic. Досі unwrap змушував нас вкладатися дедалі глибше, тоді як насправді ми хотіли просто отримати змінну назовні. Саме для цього і призначений ?.
Після виявлення Err є дві допустимі дії:
panic!, чого ми вже вирішили, якщо можливо, уникатиreturn, тому щоErrозначає, що його не можна обробити
? — це майже1 точно еквівалент unwrap, який виконує return замість panic при Err. Подивімося, як можна спростити попередній приклад, що використовував комбінатори:
use std::num::ParseIntError;
fn multiply(first_number_str: &str, second_number_str: &str) -> Result<i32, ParseIntError> {
let first_number = first_number_str.parse::<i32>()?;
let second_number = second_number_str.parse::<i32>()?;
Ok(first_number * second_number)
}
fn print(result: Result<i32, ParseIntError>) {
match result {
Ok(n) => println!("n is {}", n),
Err(e) => println!("Error: {}", e),
}
}
fn main() {
print(multiply("10", "2"));
print(multiply("t", "2"));
}
Макрос try!
До появи ? та сама функціональність досягалася за допомогою макроса try!.
Оператор ? тепер рекомендовано використовувати, але ви все ще можете зустріти try!, коли переглядаєте старіший код. Така сама функція multiply із попереднього прикладу виглядала б так із використанням try!:
// Щоб скомпілювати й запустити цей приклад без помилок, використовуючи Cargo, змініть значення
// поля `edition` у розділі `[package]` файлу `Cargo.toml` на "2015".
use std::num::ParseIntError;
fn multiply(first_number_str: &str, second_number_str: &str) -> Result<i32, ParseIntError> {
let first_number = try!(first_number_str.parse::<i32>());
let second_number = try!(second_number_str.parse::<i32>());
Ok(first_number * second_number)
}
fn print(result: Result<i32, ParseIntError>) {
match result {
Ok(n) => println!("n is {}", n),
Err(e) => println!("Error: {}", e),
}
}
fn main() {
print(multiply("10", "2"));
print(multiply("t", "2"));
}
-
Див. повернення до
?для докладнішої інформації. ↩