I am looking into best practices for error handling when it comes to functions that could return an error (could be handled with unwrap(), but instead we want to use error handling). Say I have a rust lib that has a function that simply gets an environment variable and returns it. The env::var crate returns Result<String, VarError>
. Option 1 catches the Resut or Error type in a match statement in this lib function and returns either the String read out or a blank String if there was an error (along with a print statement)
Option 1
lib.rs
pub fn fetch_env_var1() -> String {
// Instead of using unwrap(), use a match to catch the error at the lowest level
match env::var("ENV_VAR1") {
Ok(data) => {
println!("The env var1 value is: {:?}", data);
data
}
Err(e) => {
println!("Error retrieving env var1: {:?}", e);
String::new() // Return blank String
}
}
Now say this function is called by a nested function call in my main loop:
main.rs
fn example_function() -> String {
fetch_env_var1()
}
fn main() {
println!("The env var1 value is: {:?}", example_function());
}
OR is it better practice to always propagate up the errors to the highest level? i.e. this below instead:
Option 2
lib.rs
pub fn fetch_env_var1() -> Result<String, Box<dyn std::error::Error>> {
env::var("ENV_VAR1")?
}
main.rs
fn example_function() -> Result<String, Box<dyn std::error::Error>> {
fetch_env_var1()?
}
fn main() {
let output = match example_function() {
Ok(data) => {
println!("The env var1 value is: {:?}", data);
data
}
Err(e) => {
println!("Error retrieving env var1: {:?}", e);
String::new()
}
};
}
Basically, I keep getting stuck on if it is better practice to always handle errors from unwrap() at the lowest library level via a match statement OR is it better practice to always propagate errors up to the highest level of the function calls and handle them there?