I have something like this (the real function is Ini::Section::get
from rust-ini):
impl Foo { pub fn get<K>(&'a mut self, key: &K) -> Option<&'a str> where K: Hash + Eq, { // ... } }
I have to call it several times:
fn new() -> Result<Boo, String> { let item1 = match section.get("item1") { None => return Result::Err("no item1".to_string()), Some(v) => v, }; let item2 = match section.get("item2") { None => return Result::Err("no item2".to_string()), Some(v) => v, }; }
To remove code bloat, I can write a macro like this:
macro_rules! try_ini_get { ($e:expr) => { match $e { Some(s) => s, None => return Result::Err("no ini item".to_string()), } } }
Is there any way to remove the code duplication without this macro implementation?
To “unwrap” something in Rust is to say, “Give me the result of the computation, and if there was an error, panic and stop the program.” It would be better if we showed the code for unwrapping because it is so simple, but to do that, we will first need to explore the Option and Result types.
It is an enum with the variants, Ok(T) , representing success and containing a value, and Err(E) , representing error and containing an error value. Functions return Result whenever errors are expected and recoverable. In the std crate, Result is most prominently used for I/O.
Type Option represents an optional value: every Option is either Some and contains a value, or None , and does not. Option types are very common in Rust code, as they have a number of uses: Initial values. Return values for functions that are not defined over their entire input range (partial functions)
The ok_or
and ok_or_else
methods convert Option
s to Result
s, and the ?
operator automates the boilerplate associated with early Err
returns.
You could do something like:
fn new() -> Result<Boo, String> { let item1 = section.get("item1").ok_or("no item1")?; let item2 = section.get("item2").ok_or("no item2")?; // whatever processing... Ok(final_result) }
If you're using the crate anyhow
you can import the anyhow::Context
trait which adds the .context
method on Option
s to turn them into anyhow::Result
s:
use anyhow::{Result, Context}; fn new() -> Result<Boo> { let item1 = section.get("item1").context("no item1")?; let item2 = section.get("item2").context("no item2")?; // whatever processing... Ok(final_result) }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With