当两个 Options 包含可以被测试是否相等的值时,测试两个 Options 是否相等的最惯用的方法是什么?
What's the most idiomatic way to test two Options for equality when they contain values which can be tested for equality?
我有两种类型可以进行相等性测试。但是,一旦我将它们包装在 Option
中,各种 PartialEq
实现所提供的精确度就完全超过了 window。我必须使用 map
或以其他方式转换它们。
例如,让我们使用 &str
和 String
:
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>,
似乎没有技术原因阻止它,看起来只是执行工作的问题。
从 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)+))
}
});
}
我有两种类型可以进行相等性测试。但是,一旦我将它们包装在 Option
中,各种 PartialEq
实现所提供的精确度就完全超过了 window。我必须使用 map
或以其他方式转换它们。
例如,让我们使用 &str
和 String
:
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>,
似乎没有技术原因阻止它,看起来只是执行工作的问题。
从 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)+))
}
});
}