Look at this Rust code that defines a custom error and uses it in a function. What will it print?
use std::fmt;
#[derive(Debug)]
struct MyError {
details: String,
}
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Error: {}", self.details)
}
}
impl std::error::Error for MyError {}
fn might_fail(fail: bool) -> Result<&'static str, MyError> {
if fail {
Err(MyError { details: String::from("Something went wrong") })
} else {
Ok("Success")
}
}
fn main() {
match might_fail(true) {
Ok(msg) => println!("{}", msg),
Err(e) => println!("{}", e),
}
}Check what the Err variant prints using the Display trait.
The function returns an Err with MyError. The Display trait prints "Error: Something went wrong".
This code uses a custom error type but calls the function with false. What is printed?
use std::fmt;
#[derive(Debug)]
struct MyError {
details: String,
}
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Error: {}", self.details)
}
}
impl std::error::Error for MyError {}
fn might_fail(fail: bool) -> Result<&'static str, MyError> {
if fail {
Err(MyError { details: String::from("Something went wrong") })
} else {
Ok("Success")
}
}
fn main() {
match might_fail(false) {
Ok(msg) => println!("{}", msg),
Err(e) => println!("{}", e),
}
}Look at the Ok branch of the match.
When fail is false, the function returns Ok("Success"), so it prints "Success".
This code tries to create a custom error but forgets to implement a trait. What error occurs?
struct MyError {
details: String,
}
fn main() {
let err = MyError { details: String::from("Oops") };
println!("{}", err);
}Printing with {} requires the Display trait.
The struct MyError does not implement Display, so printing it with {} causes a compile error.
Choose the correct statement about creating and using custom error types in Rust.
Think about what traits Rust expects for error handling.
To use a custom error type with Result and error handling libraries, it must implement std::error::Error. Implementing Display is also required for user-friendly messages.
This Rust code defines two custom error types and nests one inside the other. What will it print?
use std::fmt;
#[derive(Debug)]
struct InnerError {
msg: String,
}
impl fmt::Display for InnerError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Inner error: {}", self.msg)
}
}
impl std::error::Error for InnerError {}
#[derive(Debug)]
struct OuterError {
source: InnerError,
}
impl fmt::Display for OuterError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Outer error caused by: {}", self.source)
}
}
impl std::error::Error for OuterError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.source)
}
}
fn main() {
let inner = InnerError { msg: String::from("disk failure") };
let outer = OuterError { source: inner };
println!("{}", outer);
}Look at how Display is implemented for OuterError.
The OuterError prints its message and then calls Display on its source, which is InnerError. So the output combines both messages.