I know that error conditions can be propagated up the call stack with '?', but at some point the errors need to be handled or generate a panic. I don't want users to see a panic, so I am trying to give more helpful messages for each case.
For example, in a simple application I have main function doing a bunch of file I/O. For each open/create/read/write function I end up with very similar code to handle errors...
let mut infile = File::open(&args.infile)
.with_context(|| format!("Failed to open file '{}'", &args.infile.display()))?;
let mut outfile = File::create(&args.outfile)
.with_context(|| format!("Failed to create file '{}'", &args.outfile.display()))?;
// We need the length of the source data
let length = infile
.seek(SeekFrom::End(0))
.with_context(|| format!("Could not seek in file '{}", &args.infile.display()))?;
infile
.seek(SeekFrom::Start(0))
.with_context(|| format!("Could not seek in file '{}", &args.infile.display()))?;
// Write a header to the file
writeln!(outfile, "SOME HEADER TEXT HERE")
.with_context(|| format!("Could not write to file '{}", &args.outfile.display()))?;
...
so there is a with_context (from the anyhow crate) for every file operation. The results are much nicer than panics, but is there a better way to do this in Rust? One of the things I like about Python is that you can put a series of operations like this in a try block and handle all the errors at the end and I am just wondering if there is a Rust equivalent?