当 PartialEq 的实现不合适时,如何断言两个变量相等?
How to assert two variables are equal when the implementation of PartialEq isn't appropriate?
在我的程序中,我用以下结构表示"events":
struct Event {
value: &'static str,
timestamp: usize,
}
到目前为止,我使用 PartialEq
来比较 Event
变量:大多数时候,我认为两个 Event
是相等的,如果它们的 value
是相同:
impl PartialEq for Event {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_loose_equality() {
let a = Event { value: "a-value", timestamp: 12345 };
let b = Event { value: "a-value", timestamp: 23456 };
assert_eq!(a, b);
}
}
然而,在某些测试中,我想确保两个这样的变量是"strictly equals":测试应该失败他们有不同的timestamp
(在[=18方面不一样) =]).
根据 assert_eq!
的文档:
Asserts that two expressions are equal to each other (using PartialEq).
source
所以,我正在寻找一个 Eq
等价物,一个 assert_Eq_eq!
排序。
(或者我误解了 Eq
的工作原理和使用方法?)
以下是我未能完成的内容:
impl Eq for Event {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_strict_equality() {
let a = Event { value: "a-value", timestamp: 12345 };
let b = Event { value: "a-value", timestamp: 12345 };
// ???
}
}
是的,你误会了什么。 Eq
没有超过 PartialEq
的任何新方法。这只是一个断言 PartialEq
的实现是自反的(以及 PartialEq
假设的传递性和对称性)。
如果你想要一个不同的 "strict" 相等性,你可以创建自己的特征(如果你希望经常使用它)或者简单地在 [=16] 上附加一个方法 fn strict_eq(&self, other: &Self) -> bool
=].
给定这样的方法,您可以编写一个宏来使用该方法。
可以找到 assert_eq!
的完整源代码 here 并且可以很容易地改编,但是(可能过于)简单的版本类似于
macro_rules! assert_strict_eq {
($left: expr, $right: expr) => {
if !$left.strict_eq(&$right) {
panic!(r#"assertion failed: `(left == right)`
left: `{:?}`,
right: `{:?}`"#, $left, $right)
}
}
}
你在逆流而上逆流而上。顺其自然。设 PartialEq
为严格相等,并为松散相等定义一个单独的特征或方法。
#[derive(Eq, PartialEq)]
struct Event { .. }
impl Event {
fn loose_eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
#[test]
fn test_loose_equality() {
let a = Event { value: "a-value", timestamp: 12345 };
let b = Event { value: "a-value", timestamp: 23456 };
assert!(a.loose_eq(b));
}
我会根据需要创建 "views" 类型:
struct Event {
value: &'static str,
timestamp: usize,
}
#[derive(Debug, PartialEq)]
struct Exact<'a> {
value: &'a &'static str,
timestamp: &'a usize,
}
impl Event {
fn exact(&self) -> Exact<'_> {
let Self { value, timestamp } = self;
Exact { value, timestamp }
}
}
fn demo(a: Event, b: Event) {
assert_eq!(a.exact(), b.exact());
}
这里我选择引用每个字段来演示一般情况,但您不需要引用这个特定示例(&str
和 usize
实现 Copy
并且很小)。
您也可以选择根本不在原始类型上实现 PartialEq
,而 仅 通过视图执行比较:
assert_eq!(a.exact(), b.exact());
assert_eq!(a.loose(), b.loose());
与 JavaScript 不同,Rust 不支持相等与严格相等。
但是,您可以通过实现自己的特征和宏来实现类似的效果:
pub trait StrictEq {
fn strict_eq(&self, other: &Self) -> bool;
}
macro_rules! assert_strict_eq {
($left:expr, $right:expr) => {{
match (&$left, &$right) {
(left_val, right_val) => {
assert!(left_val.strict_eq(right_val));
}
}
}};
}
Event
的实现相当简单:
impl StrictEq for Event {
fn strict_eq(&self, other: &Self) -> bool {
self.value == other.value && self.timestamp == other.timestamp
}
}
如果你只在测试中需要严格相等,而你的结构只有两个字段,我会直接比较这些字段:
let a = Event { value: "a-value", timestamp: 12345 };
let b = Event { value: "a-value", timestamp: 12345 };
assert_eq!(a.value, b.value);
assert_eq!(a.timestamp, b.timestamp);
对我来说,这看起来是最简单、最易读的选项。
在我的程序中,我用以下结构表示"events":
struct Event {
value: &'static str,
timestamp: usize,
}
到目前为止,我使用 PartialEq
来比较 Event
变量:大多数时候,我认为两个 Event
是相等的,如果它们的 value
是相同:
impl PartialEq for Event {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_loose_equality() {
let a = Event { value: "a-value", timestamp: 12345 };
let b = Event { value: "a-value", timestamp: 23456 };
assert_eq!(a, b);
}
}
然而,在某些测试中,我想确保两个这样的变量是"strictly equals":测试应该失败他们有不同的timestamp
(在[=18方面不一样) =]).
根据 assert_eq!
的文档:
Asserts that two expressions are equal to each other (using PartialEq). source
所以,我正在寻找一个 Eq
等价物,一个 assert_Eq_eq!
排序。
(或者我误解了 Eq
的工作原理和使用方法?)
以下是我未能完成的内容:
impl Eq for Event {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_strict_equality() {
let a = Event { value: "a-value", timestamp: 12345 };
let b = Event { value: "a-value", timestamp: 12345 };
// ???
}
}
是的,你误会了什么。 Eq
没有超过 PartialEq
的任何新方法。这只是一个断言 PartialEq
的实现是自反的(以及 PartialEq
假设的传递性和对称性)。
如果你想要一个不同的 "strict" 相等性,你可以创建自己的特征(如果你希望经常使用它)或者简单地在 [=16] 上附加一个方法 fn strict_eq(&self, other: &Self) -> bool
=].
给定这样的方法,您可以编写一个宏来使用该方法。
可以找到 assert_eq!
的完整源代码 here 并且可以很容易地改编,但是(可能过于)简单的版本类似于
macro_rules! assert_strict_eq {
($left: expr, $right: expr) => {
if !$left.strict_eq(&$right) {
panic!(r#"assertion failed: `(left == right)`
left: `{:?}`,
right: `{:?}`"#, $left, $right)
}
}
}
你在逆流而上逆流而上。顺其自然。设 PartialEq
为严格相等,并为松散相等定义一个单独的特征或方法。
#[derive(Eq, PartialEq)]
struct Event { .. }
impl Event {
fn loose_eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
#[test]
fn test_loose_equality() {
let a = Event { value: "a-value", timestamp: 12345 };
let b = Event { value: "a-value", timestamp: 23456 };
assert!(a.loose_eq(b));
}
我会根据需要创建 "views" 类型:
struct Event {
value: &'static str,
timestamp: usize,
}
#[derive(Debug, PartialEq)]
struct Exact<'a> {
value: &'a &'static str,
timestamp: &'a usize,
}
impl Event {
fn exact(&self) -> Exact<'_> {
let Self { value, timestamp } = self;
Exact { value, timestamp }
}
}
fn demo(a: Event, b: Event) {
assert_eq!(a.exact(), b.exact());
}
这里我选择引用每个字段来演示一般情况,但您不需要引用这个特定示例(&str
和 usize
实现 Copy
并且很小)。
您也可以选择根本不在原始类型上实现 PartialEq
,而 仅 通过视图执行比较:
assert_eq!(a.exact(), b.exact());
assert_eq!(a.loose(), b.loose());
与 JavaScript 不同,Rust 不支持相等与严格相等。
但是,您可以通过实现自己的特征和宏来实现类似的效果:
pub trait StrictEq {
fn strict_eq(&self, other: &Self) -> bool;
}
macro_rules! assert_strict_eq {
($left:expr, $right:expr) => {{
match (&$left, &$right) {
(left_val, right_val) => {
assert!(left_val.strict_eq(right_val));
}
}
}};
}
Event
的实现相当简单:
impl StrictEq for Event {
fn strict_eq(&self, other: &Self) -> bool {
self.value == other.value && self.timestamp == other.timestamp
}
}
如果你只在测试中需要严格相等,而你的结构只有两个字段,我会直接比较这些字段:
let a = Event { value: "a-value", timestamp: 12345 };
let b = Event { value: "a-value", timestamp: 12345 };
assert_eq!(a.value, b.value);
assert_eq!(a.timestamp, b.timestamp);
对我来说,这看起来是最简单、最易读的选项。