rust - 当两个 Options 包含可以被测试是否相等的值时,测试两个 Options 是否相等的最惯用的方法是什么?

标签 rust

我有两种类型可以进行相等性测试。然而,一旦我将它们包装在 Option 中,各种 PartialEq 实现所提供的精确性就完全消失了。我必须使用 map 或以其他方式转换它们。

例如,让我们使用&strString:

fn main() {
    let a = "hello";
    let b = "hello".to_owned();

    assert_eq!(a, b); // Just fine

    let a = Some(a);
    let b = Some(b);

    // error: mismatched types
    assert_eq!(a, b);

    // error: mismatched types
    assert_eq!(a, b.as_ref());

    // works, but highly tied to strings or slices,
    // requires me to remember which is which
    assert_eq!(a, b.as_ref().map(|x| &x[..]));
}

肯定有更简单或更直接的方法来做到这一点?

附带问题 — 是什么阻止了 Option 更广泛地实现 PartialEq?我在猜测连贯性,我的宿敌

impl<T, U> PartialEq<Option<U>> for Option<T>
where
    T: PartialEq<U>,

RFCs 中有一些关于这个的讨论和 Rust 问题(12)。

最佳答案

从 Rust 1.40 开始,您可以使用 as_deref()所以你不必记住什么是什么:

assert_eq!(a.as_deref(), b.as_deref());

在 Rust 1.40 之前,我会做这样的事情:

match (&a, &b) {
    (Some(a), Some(b)) => assert_eq!(a, b),
    (None, None) => (),
    _ => panic!("a and b not equal"),
}

另一个选项是自定义断言,基于 assert_eq! :

macro_rules! cmp_eq_option {
    ($left:expr, $right:expr) => {{
        match (&$left, &$right) {
            (Some(left_val), Some(right_val)) => *left_val == *right_val,
            (None, None) => true,
            _ => false,
        }
    }};
}

#[macro_export]
macro_rules! assert_eq_option {
    ($left:expr, $right:expr) => ({
        if !cmp_eq_option!($left, $right) {
            panic!(r#"assertion failed: `(left == right)`
  left: `{:?}`,
 right: `{:?}`"#, $left, $right)
        }
    });
    ($left:expr, $right:expr,) => ({
        assert_eq_option!($left, $right)
    });
    ($left:expr, $right:expr, $($arg:tt)+) => ({
        if !cmp_eq_option!($left, $right) {
            panic!(r#"assertion failed: `(left == right)`
  left: `{:?}`,
 right: `{:?}`: {}"#, $left, $right, format_args!($($arg)+))
        }
    });
}

关于rust - 当两个 Options 包含可以被测试是否相等的值时,测试两个 Options 是否相等的最惯用的方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30429801/

相关文章:

rust - 如何在Rocket/Juniper上下文中使用PickleDB?

rust - 预期的 &-ptr,在遍历元组数组时找到元组

generics - 即使 `AsRef` 存在足够长的时间,借用的值对于 `self` 结果来说也没有足够长的存在

rust - 如何编写盒装闭包的类型,该闭包将引用作为参数并返回引用参数中数据的对象?

rust - 改进 Rust 的 Future 以不创建单独的线程

rust - 返回生命周期受参数生命周期限制的迭代器的特征

generics - 实现返回带有闭包的结构的工厂函数

rust - Clippy提示严格的f32比较

rust - Rust 中的 "one type is more general than the other"错误,而类型相同

http - 如何从 Rust 发出 HTTP 请求?