Tratamento de Erros
O operador ? é uma forma abreviada de propagar um Result: se a expressão for Err, ? retorna esse erro imediatamente da função atual; se for Ok, ? desembrulha o valor e a execução continua. s.parse()? abaixo ou te dá um i32 válido ou sai antecipadamente de parse_and_double com o erro de parse.
use std::num::ParseIntError;
fn parse_and_double(s: &str) -> Result<i32, ParseIntError> {
let n: i32 = s.parse()?;
Ok(n * 2)
}
fn main() {
match parse_and_double("21") {
Ok(n) => println!("Doubled: {}", n),
Err(e) => println!("Error: {}", e),
}
match parse_and_double("not a number") {
Ok(n) => println!("Doubled: {}", n),
Err(e) => println!("Error: {}", e),
}
}Doubled: 42 Error: invalid digit found in string
Um tipo de erro personalizado
Para suas próprias funções, um tipo de erro personalizado — mesmo um simples como NegativeNumberError — costuma ser mais claro do que reutilizar um erro genérico. Implementar o trait Display para ele é o que permite que {} o formate diretamente dentro de println!.
use std::fmt;
#[derive(Debug)]
struct NegativeNumberError;
impl fmt::Display for NegativeNumberError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "number must not be negative")
}
}
fn square_root_ish(n: i32) -> Result<f64, NegativeNumberError> {
if n < 0 {
return Err(NegativeNumberError);
}
Ok((n as f64).sqrt())
}
fn main() {
match square_root_ish(16) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e),
}
match square_root_ish(-4) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e),
}
}Result: 4 Error: number must not be negative
Próximo: collections e a biblioteca padrão — HashMap, e um último olhar sobre o que mais a biblioteca padrão do Rust oferece.
Practice Exercise
Escreva uma função safe_divide(a: f64, b: f64) -> Result<f64, String> que retorne Err("cannot divide by zero".to_string()) se b for 0.0, ou Ok(a / b) caso contrário. Chame-a com (10.0, 0.0), faça match do resultado, e imprima a mensagem de erro se for Err.