However it looks like when the main is terminated without a panic, just because a Result <_, Error> is involved, like:
use std::fs::File;
fn main() -> Result<(), Error> {
let _ = File::open("bar.txt").map_err(|_| err_msg("test"))?;
Ok(())
}
Some other customization trick should be used. Which one?
PS The default implementation printing an error is probably fine, however it's CGI program and it needs to show a message in a browser, and using stderr doesn't work.
It's very straightforward to handle all errors in main, print them the way you want, and return Ok(()) or call exit. Why would you need something else?
I understand that there are tons work around, we will consider them after somebody clearly assured me: no, customization of that is impossible unless you want to rewrite runtime.
Why is handling errors a work around? Error handling is something we do in every function, so why not in main? I think customizing the way main works would be a work around if normal error handling doesn't work (but it does).
To ensure that you don't return an error here (since you don't want it to be printed), define main without a return type (as you would do with any other function): fn main() {
fn main() {
if let Err(e) = inner_main() {
// Implement your custom error printing logic
// For example:
log::error!("{e:#?}");
}
}
fn inner_main() -> Result<(), Error> {
// You can ergonomically use ? here
some_fallible_code()?;
Ok(())
}
It looks like you used a String as your error type based on that representation in your screenshot, which is generally discouraged. The main options for an error type are:
Box<dyn std::error::Error>: simple, but missing some things (you should probably add Send + Sync bounds, it doesn’t have a backtrace, no chainable error causes, …)
anyhow::Error: A “better” version of Box<dyn Error>, with support for context, chains of causes, and backtraces.
Custom Error type: also fine, but will likely be one giant enum with tons of variants for every library’s error type. You would probably like to use thiserror for ergonomics.
Also, if your errors are going to be printed out to a user, Display is probably more correct to use than Debug (Debug is for “a programmer-facing, debugging context”, whereas Display is “for user-facing output”).
If you’re done with the topic, you can mark someone’s post as the solution.
Honestly I do not know which error type I use. I use io::Result<()>, and it's a native in most cases. But somewhere I convert to it using map_err when Result is incompatible or it's Option. Since errors are very rare in my case, I do not care much about a perfect processing them. I started worrying about getting some message after the root edited some my files and I didn't notice that until I realized that I lost some work due that. Changes couldn't be saved, but I didn't know that. So just some error message is fine for now. No detail investigation is necessary.