Convertendo Tipos de Erro
use std::error::Error; use std::fmt::{self, Display, Formatter}; use std::fs::{self, 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(filename) => write!(f, "Nome de usuário não encontrado em {filename}"), } } } impl From<io::Error> for ReadUsernameError { fn from(err: io::Error) -> ReadUsernameError { ReadUsernameError::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() { //fs::write("config.dat", "").unwrap(); let username = read_username("config.dat"); println!("nome_usuario ou erro: {username:?}"); }
Pontos chave:
- A variável
nome_usuariopode serOk(string)ouErr(error). - Use a chamada
fs::writepara testar os diferentes cenários: nenhum arquivo, arquivo vazio e arquivo com nome de usuário.
É uma boa prática para todos os tipos de erro que não precisam ser no_std implementar std::error::Error, que requer Debug e Display. O crate Error para core só está disponível em nightly, então ainda não é totalmente compatível com no_std.
Geralmente é útil para eles implementar Clone e Eq também quando possível, para tornar mais fácil a vida para testes e consumidores da sua biblioteca. Neste caso, não podemos fazê-lo facilmente, porque io::Error não os implementa.