Rust language from entry to master series - how to judge whether objects are equal?

rust_tutorial_logo.pngIn the Rust language, PartialEq and Eq are two very important traits. They are used to compare values ​​of types, PartialEq is used to compare partial equality (not necessarily exact equality), and Eq is used to compare exact equality.

In Rust, any type can implement PartialEq and Eq, so these two traits are very flexible.

Basic usage

compare integers

fn main() {
    let a = 10;
    let b = 20;
    if a == b {
        println!("a equals b");
    } else {
        println!("a does not equal b");
    }
}
复制代码

output:

a does not equal b
复制代码

compare strings

fn main() {
    let a = "hello";
    let b = "world";
    if a == b {
        println!("a equals b");
    } else {
        println!("a does not equal b");
    }
}
复制代码

output:

a does not equal b
复制代码

Compare custom types

#[derive(PartialEq, Eq)]
struct Person {
    name: String,
    age: u8,
}

fn main() {
    let p1 = Person {
        name: "Alice".to_string(),
        age: 30,
    };
    let p2 = Person {
        name: "Bob".to_string(),
        age: 30,
    };
    if p1 == p2 {
        println!("p1 equals p2");
    } else {
        println!("p1 does not equal p2");
    }
}
复制代码

output:

p1 does not equal p2
复制代码

Compare floating point numbers

fn main() {
    let a = 0.1 + 0.2;
    let b = 0.3;
    if a == b {
        println!("a equals b");
    } else {
        println!("a does not equal b");
    }
}
复制代码

output:

a does not equal b
复制代码

custom comparison function

#[derive(PartialEq, Eq)]
struct Person {
    name: String,
    age: u8,
}

impl PartialEq for Person {
    fn eq(&self, other: &Self) -> bool {
        self.age == other.age
    }
}

impl Eq for Person {}

fn main() {
    let p1 = Person {
        name: "Alice".to_string(),
        age: 30,
    };
    let p2 = Person {
        name: "Bob".to_string(),
        age: 30,
    };
    if p1 == p2 {
        println!("p1 equals p2");
    } else {
        println!("p1 does not equal p2");
    }
}
复制代码

output:

p1 equals p2
复制代码

Comparing enumerated types

#[derive(PartialEq, Eq)]
enum Color {
    Red,
    Blue,
}

fn main() {
    let c1 = Color::Red;
    let c2 = Color::Blue;
    if c1 == c2 {
        println!("c1 equals c2");
    } else {
        println!("c1 does not equal c2");
    }
}
复制代码

output:

c1 does not equal c2
复制代码

Use the assert_eq! macro

fn main() {
    let a = 10;
    let b = 20;
    assert_eq!(a, b);
}
复制代码

output:

thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `10`,
 right: `20`', src/main.rs:4:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
复制代码

Use the assert_ne! macro

fn main() {
    let a = 10;
    let b = 20;
    assert_ne!(a, b);
}
复制代码

output:

thread 'main' panicked at 'assertion failed: `(left != right)`
  left: `10`,
 right: `10`', src/main.rs:4:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
复制代码

Advanced usage

custom comparison function

#[derive(PartialEq, Eq)]
struct Person {
    name: String,
    age: u8,
}

impl PartialEq for Person {
    fn eq(&self, other: &Self) -> bool {
        self.age == other.age
    }
}

impl Eq for Person {}

fn main() {
    let p1 = Person {
        name: "Alice".to_string(),
        age: 30,
    };
    let p2 = Person {
        name: "Bob".to_string(),
        age: 40,
    };
    if p1 == p2 {
        println!("p1 equals p2");
    } else {
        println!("p1 does not equal p2");
    }
}
复制代码

output:

p1 does not equal p2
复制代码

use generics

#[derive(PartialEq, Eq)]
struct Pair<T> {
    first: T,
    second: T,
}

fn main() {
    let p1 = Pair {
        first: 1,
        second: 2,
    };
    let p2 = Pair {
        first: 2,
        second: 1,
    };
    if p1 == p2 {
        println!("p1 equals p2");
    } else {
        println!("p1 does not equal p2");
    }
}
复制代码

output:

p1 does not equal p2
复制代码

Using PartialOrd and Ord

#[derive(PartialEq, Eq, PartialOrd, Ord)]
struct Person {
    name: String,
    age: u8,
}

fn main() {
    let p1 = Person {
        name: "Alice".to_string(),
        age: 30,
    };
    let p2 = Person {
        name: "Bob".to_string(),
        age: 40,
    };
    if p1 < p2 {
        println!("p1 is younger than p2");
    } else {
        println!("p1 is older than or equal to p2");
    }
}
复制代码

output:

p1 is younger than p2
复制代码

Using Debug and Display

#[derive(Debug, PartialEq, Eq)]
struct Person {
    name: String,
    age: u8,
}

use std::fmt;

impl fmt::Display for Person {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} ({})", self.name, self.age)
    }
}

fn main() {
    let p1 = Person {
        name: "Alice".to_string(),
        age: 30,
    };
    let p2 = Person {
        name: "Bob".to_string(),
        age: 40,
    };
    println!("p1: {}", p1);
    println!("p2: {}", p2);
}
复制代码

output:

p1: Alice (30)
p2: Bob (40)
复制代码

Best Practices

When implementing PartialEq and Eq, the following points should be considered:

  • For custom types, all member variables should be compared, not just some.
  • For floating-point numbers, approximate comparisons should be used instead of exact comparisons.
  • For enumeration types, all member variables should be compared, not just the enumeration value itself.
  • If the type to be compared implements PartialOrd and Ord, these two traits should be used first.

in conclusion

In the Rust language, PartialEq and Eq are very important traits for comparing values ​​of types. These two traits are so flexible that any type can implement them. When implementing PartialEq and Eq, you should consider the characteristics of the type, compare all member variables, use approximate comparison, and so on.

Guess you like

Origin juejin.im/post/7222294792893136933