Thanks. I'll have a look at thiserror later.
The problem I had with the question mark is that some functions returned a Result<T,std::io::Error>
, whereas others returned a Result<T,ZipErrpr>
and others returned Option
s. So the issue that had me stumped is that of finding a single return type that is compatible with all of these. (So using the question mark wherever I was using an unwrap led to compile errors. I get that the function needs to return a Result<T,E>
, and I'm clear on what type the T
is (Vec<u8>
), but had no clue what the E
should be. I'll also have a play with cargo expand so as to see what thiserror does.)
Ok. So writing the above led me to try and come up with the simplest example of what I was struggling with (albeit a completely artificial example, whereas the one I originally gave had a practical result I was trying to achieve). The result was:
fn one() -> Result<i32,i32> {
Err(1)
}
fn two() -> Result<f32,f32> {
Err(2.0)
}
fn combine() -> Result<f32,i32> {
let x = one()?;
let y = two()?;
if x != 0 {
Ok(0.0)
} else {
Ok(1.0)
}
}
fn main() {
let a = combine();
match a {
Err(x) => println!("Error {}",x),
Ok(x) => println!("Ok {}",x),
}
}
This gave the following error
7 | fn combine() -> Result<f32,i32> {
| --------------- expected `i32` because of this
8 | let x = one()?;
9 | let y = two()?;
| ^ the trait `From<f32>` is not implemented for `i32`
And, after having read about #[from]
in thiserror
(thanks for the above), I came up with the following
use std::convert::From;
use std::fmt;
// See https://doc.rust-lang.org/std/convert/trait.From.html
// this is the Err type that combine() will return
#[derive(Debug)]
enum MyError {
FError(f32),
IError(i32),
}
// this is so that we can convert from a Err(i32) or Err(f32) to an Err(MyError)
impl From<i32> for MyError {
fn from(value: i32) -> Self {
MyError::IError(value)
}
}
impl From<f32> for MyError {
fn from(value: f32) -> Self {
MyError::FError(value)
}
}
// This is so we can println!() our error
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MyError::FError(value) => write!(f, "FError: {}", value),
MyError::IError(value) => write!(f, "IError: {}", value)
}
}
}
// totally artificial example where two functions return Results but with different Err types
fn one() -> Result<i32,i32> {
Err(1)
}
fn two() -> Result<f32,f32> {
Err(2.0)
}
fn combine() -> Result<f32,MyError> {
let x = one()?;
let y = two()?;
if x != 0 {
Ok(0.0)
} else if y != 0.0 {
Ok(2.0)
} else {
Ok(1.0)
}
}
fn main() {
let a = combine();
match a {
Err(x) => println!("Error {}",x),
Ok(x) => println!("Ok {}",x),
}
}