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
.