Conversões Try
A expansão efetiva do operador ? é um pouco mais complicada do que indicado anteriormente:
expression?
funciona da mesma forma que
match expression {
Ok(value) => value,
Err(err) => return Err(From::from(err)),
}
A chamada From::from aqui significa que tentamos converter o tipo de erro para o tipo retornado pela função. Isso torna fácil encapsular erros em erros de nível superior.
Exemplo
use std::error::Error; use std::fmt::{self, Display, Formatter}; use std::fs::File; use std::io::{self, Read}; #[derive(Debug)] enum ReadUsernameError { IoError(io::Error), EmptyUsername(String), } impl Error for ReadUsernameError {} impl Display for ReadUsernameError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { Self::IoError(e) => write!(f, "Erro E/S: {e}"), Self::EmptyUsername(path) => write!(f, "Nome de usuário não encontrado em {path}"), } } } impl From<io::Error> for ReadUsernameError { fn from(err: io::Error) -> Self { Self::IoError(err) } } fn read_username(path: &str) -> Result<String, ReadUsernameError> { let mut username = String::with_capacity(100); File::open(path)?.read_to_string(&mut username)?; if username.is_empty() { return Err(ReadUsernameError::EmptyUsername(String::from(path))); } Ok(username) } fn main() { //std::fs::write("config.dat", "").unwrap(); let username = read_username("config.dat"); println!("username ou erro: {username:?}"); }
O operador ? deve retornar um valor compatível com o tipo de retorno da função. Para Result, isso significa que os tipos de erro devem ser compatíveis. Uma função que retorna Result<T, ErrorOuter> só pode usar ? em um valor do tipo Result<U, ErrorInner> se ErrorOuter e ErrorInner forem do mesmo tipo ou se ErrorOuter implementar From<ErrorInner>.
Uma alternativa comum a uma implementação From é Result::map_err, especialmente quando a conversão ocorre apenas em um local.
Não há requisito de compatibilidade para Option. Uma função que retorna Option<T> pode usar o operador ? em Option<U> para tipos T e U arbitrários.
Uma função que retorna Result não pode usar ? em Option e vice-versa. No entanto, Option::ok_or converte Option em Result, enquanto Result::ok transforma Result em Option.