Macro nar_dev_utils::unwrap_or_return

source ·
macro_rules! unwrap_or_return {
    (? $option:expr) => { ... };
    (? $option:expr => continue $($code:tt)*) => { ... };
    (? $option:expr => break $($code:tt)*) => { ... };
    (? $option:expr => $default:expr) => { ... };
    (@ $result:expr) => { ... };
    (@ $result:expr => continue $($code:tt)*) => { ... };
    (@ $result:expr, $err:pat => break $($code:tt)*) => { ... };
    (@ $result:expr, $err:pat => $default:expr) => { ... };
}
Expand description

§解包或返回

  • 📝类似Rust自带的?语法,支持在None/Err时返回不同的值
  • ✨允许将类似?语法用在非Option/Result的函数环境中

§用例

use nar_dev_utils::unwrap_or_return;

/// 用例1 @ `Option<T>`
fn f() -> Option<usize> {
    // 解包`Some`
    let option = Some(1);
    let a = unwrap_or_return!(?option => None); // 等价于`option?`
    assert_eq!(a, 1);
    // 解包`None` | ✅支持返回其它的默认值
    let option = None;
    unwrap_or_return!(?option => Some(0));
    // 最终不可达
    unreachable!("因为对None解包提前返回,故此处代码不可达")
}
assert_eq!(f(), Some(0));

/// 用例2 @ `Result<T,E>`
fn g(err_default: impl FnOnce(usize) -> usize) -> Result<i32, usize> {
    // 解包`Ok`
    let result = Ok(1);
    let a = unwrap_or_return!(@result, x => Err(x)); // 使用`result?`则会出现「类型不明确」错误
    assert_eq!(a, 1);
    // 解包`Err` | ✅支持返回其它的默认值
    let result = Err(2);
    unwrap_or_return!(@result, x => Err(err_default(x)));
    // 最终不可达
    unreachable!("因为对Err解包提前返回,故此处代码不可达")
}
assert_eq!(g(|x| x + 1), Err(2 + 1));
assert_eq!(g(|x| x - 2), Err(0));

/// 用例3 @ 非`Option`/`Result`环境
fn h1(x: Option<usize>, default: usize) -> usize {
    // 解包Some,对None返回默认值
    let result = unwrap_or_return!(?x => default);
    result + 1
}
assert_eq!(h1(Some(1), 0), 1 + 1);
assert_eq!(h1(Some(2), 0), 2 + 1);
assert_eq!(h1(None, 0), 0);
assert_eq!(h1(None, 1), 1);

/// 用例4 @ 非`Option`/`Result`环境
fn h2(counter: &mut usize, x: Option<usize>, y: Result<usize, ()>, z: usize) {
    // 尝试解包x并将其附加于counter
    let x = unwrap_or_return!(?x);
    *counter += x;
    // 尝试解包y并将其附加于counter
    let y = unwrap_or_return!(@y);
    *counter += y;
    // 最终加上z
    *counter += z;
}
let mut counter = 0;
h2(&mut counter, Some(1), Ok(1), 1); // +3
assert_eq!(counter, 3);
h2(&mut counter, Some(1), Ok(1), 0); // +2
assert_eq!(counter, 5);
h2(&mut counter, Some(1), Err(()), 1); // +1
assert_eq!(counter, 6);
h2(&mut counter, None, Ok(1), 1); // +0
assert_eq!(counter, 6);

/// 用例5 @ 控制流 `break (value)`
fn sum_len(vec: impl Into<Vec<usize>>) -> (usize, usize) {
    let mut vec = vec.into();
    let mut sum = 0;
    let mut len = 0;
    loop {
        sum += unwrap_or_return!(
            ?vec.pop() // 弹出元素
            => break (sum, len) // 没了⇒返回(总和, 长度)
        );
        len += 1;
    }
}
assert_eq!(sum_len([]), (0, 0));
assert_eq!(sum_len([1, 2, 3]), (6, 3));
assert_eq!(sum_len([1, 1, 1]), (3, 3));
assert_eq!(sum_len([3, 3]), (6, 2));
assert_eq!(sum_len([2, 2, 2]), (6, 3));

/// 用例5 @ 控制流 `continue`
fn flat_options_rev(vec: impl Into<Vec<Option<usize>>>) -> Vec<usize> {
    let mut vec = vec.into();
    let mut result = vec![];
    loop {
        // * 🚩从数组中取出最后一个元素,若空则返回结果
        let option = unwrap_or_return!(?vec.pop() => break result);
        // * 🚩从元素中解包出value,若无则跳到下一个
        let value = unwrap_or_return!(?option => continue);
        // * 🚩添加元素
        result.push(value);
    }
}
assert_eq!(flat_options_rev([]), []);
assert_eq!(flat_options_rev([Some(1)]), [1]);
assert_eq!(flat_options_rev([Some(1), None]), [1]);
assert_eq!(flat_options_rev([Some(1), None, None]), [1]);
assert_eq!(flat_options_rev([Some(1), None, None, Some(2)]), [2, 1]);
assert_eq!(flat_options_rev([Some(2), None, None, Some(1)]), [1, 2]);
assert_eq!(flat_options_rev([Some(2), None, Some(1), None]), [1, 2]);
assert_eq!(flat_options_rev([Some(2), Some(1), None, None]), [1, 2]);
assert_eq!(flat_options_rev([Some(2), None, Some(1), Some(0)]), [0, 1, 2]);
assert_eq!(flat_options_rev([Some(2), Some(0), None, Some(1)]), [1, 0, 2]);

/// 用例6 @ 分立控制流 `break 'block`
fn flat_option_pairs<T>(iter: impl IntoIterator<Item = [Option<T>; 2]>) -> Vec<T> {
    let mut result = vec![];
    for [x, y] in iter {
        // * 🚩试着拿出第一个非空元素
        'x: {
            // * 🚩从元素中解包出value,若无则不做操作
            let value = unwrap_or_return!(?x => break 'x ());
            // * 🚩添加元素
            result.push(value);
        }
        // * 🚩试着拿出第二个非空元素
        'y: {
            // * 🚩从元素中解包出value,若无则不做操作
            let value = unwrap_or_return!(?y => break 'y ());
            // * 🚩添加元素
            result.push(value);
        }
    }
    result
}
let (s, null) = (Some, None);
assert_eq!(flat_option_pairs::<usize>([]), []);
assert_eq!(flat_option_pairs([[s(1), null]]), [1]);
assert_eq!(flat_option_pairs([[null, s(1)]]), [1]);
assert_eq!(flat_option_pairs([[s(1), null], [null, null]]), [1]);
assert_eq!(flat_option_pairs([[null, s(1)], [null, null]]), [1]);
assert_eq!(flat_option_pairs([[s(1), null], [null, s(2)]]), [1, 2]);
assert_eq!(flat_option_pairs([[s(2), null], [null, s(1)]]), [2, 1]);
assert_eq!(flat_option_pairs([[s(2), null], [s(1), null]]), [2, 1]);
assert_eq!(flat_option_pairs([[s(2), s(1)], [null, null]]), [2, 1]);
assert_eq!(flat_option_pairs([[s(2), null], [s(1), s(0)]]), [2, 1, 0]);
assert_eq!(flat_option_pairs([[s(2), s(0)], [null, s(1)]]), [2, 0, 1]);