We've seen that the Option enum can be used as a return value from functions
that may fail, where None can be returned to indicate failure. However,
sometimes is important to express why an operation failed. To do this we have
the Result enum.
The Result<T, E> enum has two variants:
Ok(value) which indicates that the operation succeeded, and wraps the
value returned by the operation. (value has type T)
Err(why), which indicates that the operation failed, and wraps why,
which (hopefully) explains the cause of the failure. (why has type E)
mod checked {
// For .ln() and .sqrt()
use std::num::Float;
// Mathematical "errors" we want to catch
#[deriving(Show)]
pub enum MathError {
DivisionByZero,
NegativeLogarithm,
NegativeSquareRoot,
}
pub type MathResult = Result<f64, MathError>;
pub fn div(x: f64, y: f64) -> MathResult {
if y == 0.0 {
// This operation would `fail`, instead let's return the reason of
// the failure wrapped in `Err`
Err(MathError::DivisionByZero)
} else {
// This operation is valid, return the result wrapped in `Ok`
Ok(x / y)
}
}
pub fn sqrt(x: f64) -> MathResult {
if x < 0.0 {
Err(MathError::NegativeSquareRoot)
} else {
Ok(x.sqrt())
}
}
pub fn ln(x: f64) -> MathResult {
if x < 0.0 {
Err(MathError::NegativeLogarithm)
} else {
Ok(x.ln())
}
}
}
// `op(x, y)` === `sqrt(ln(x / y))`
fn op(x: f64, y: f64) -> f64 {
// This is a three level match pyramid!
match checked::div(x, y) {
Err(why) => panic!("{}", why),
Ok(ratio) => match checked::ln(ratio) {
Err(why) => panic!("{}", why),
Ok(ln) => match checked::sqrt(ln) {
Err(why) => panic!("{}", why),
Ok(sqrt) => sqrt,
},
},
}
}
fn main() {
// Will this fail?
println!("{}", op(1.0, 10.0));
}