Option and Result
Takeaways from ...
code snippets from Logan Smith:
https://www.youtube.com/watch?v=s5S2Ed5T-dc
enum Result<T, E> {
Ok(T),
Err(E)
}
enum Option<T> {
Some(T),
None
}
Result
is a generalization ofOption
.- For
Result
there is a custome TypeE
if the value is not valid. ForOption
there is only one represented byNone
(i.e. there is only one obvious reason that this function could fail)
result.ok()
------------------------->
Result<T, E> Option<T>
<-------------------------
opt.ok_or(e)
opt.ok_or_else(|| f(x))
Operand?
match operand {
Ok(x) => x,
Err(e) => return Err(From::from(e)),
}
example:
#![allow(unused)] fn main() { struct W(String, String); fn fallible(_: u8) -> Result<String, E> { todo!(); } impl W { fn new(x: u8, y:u8) -> Result<Self, E> { // short circuit the function and returns the error // if either fallible() fails let x = fallible(x)?; let y = fallible(y)?; Ok(Self(x, y)) } // does the same thing fn new_v2(x: u8, y:u8) -> Result<Self, E> { Ok(Self(fallible(x)?, fallible(y)?)) } } // general: struct W(Vec<String>); impl W { fn new(v:&[u8]) -> Result<Self, E> { let v = v.iter() .map( |&x| fallible(x)) .collect::<Result<Vec<_>, _>>(); Ok(Self(v?)) } } }
Example 2:
#![allow(unused)] fn main() { #[derive(Debug)] struct Node { /**/ } #[derive(Debug)] enum GrandparentError{ NoParent, NoGrandparent } // the derive_more::From allows to convert Either GrandparentError // or IOError into LogGpError // optionally use thiserror::Error #[derive(Debug, derive_more::From)] enum LogGpError { GrandparentError(GE), IOError(io::Error), } impl Node { fn parent(&self) -> Option<&Node> { todo!(); } fn grandparent(n: &Node) -> Result<&Node, GrandparentError> { Ok( n.parent().ok_or(GrandparentError::NoParent)? .parent().ok_or(GrandparentError::NoGrandparent)? ) } fn log_gp(n: &Node) -> Result<(), LogGpError> { let g = grandparent(n)?; // may throw GrandparentError fs::write(/**/)?; // may throw IOError } // anyhow::Result - dynamically works with any error type... // (with a cost ... with its own vtable) fn log_gp(n: &Node) -> anyhow::Result<()> { let g = grandparent(n)?; // may throw GrandparentError fs::write(/**/)?; // may throw IOError } } }
Infallible
#![allow(unused)] fn main() { // e.g. enum Result<bool, Infallible> { Ok(bool), // 2 possible values Err(Infallible), // ZERO possible value } // e.g. impl FromStr for Wrapper { type Err = Infallible; // CAN NOT FAIL! fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(Self(s.into())) } } }
References
Study of std::io::Error
https://www.youtube.com/watch?v=s5S2Ed5T-dc