The idea of StructuralEq
and StructuralPartialEq
is pretty clear - making sure the type compatible with constant pattern matching. As docs say that couldn't be achieved with bare Eq
and PartialEq
, because of cases like this:
In a more ideal world, we could check that requirement by just checking that the given type implements both the
StructuralPartialEq
trait and theEq
trait. However, you can have ADTs that doderive(PartialEq, Eq)
, and be a case that we want the compiler to accept, and yet the constant’s type fails to implementEq
.Namely, a case like this:
#[derive(PartialEq, Eq)] struct Wrap<X>(X); fn higher_order(_: &()) { } const CFN: Wrap<fn(&())> = Wrap(higher_order); fn main() { match CFN { CFN => {} _ => {} } }
(The problem in the above code is that
Wrap<fn(&())>
does not implementPartialEq
, norEq
, becausefor<'a> fn(&'a _)
does not implement those traits.)Therefore, we cannot rely on naive check for
StructuralPartialEq
and mereEq
.As a hack to work around this, we use two separate traits injected by each of the two derives (
#[derive(PartialEq)]
and#[derive(Eq)]
) and check that both of them are present as part of structural-match checking.
I recreated the example, like this:
use std::fmt::Debug;
#[derive(PartialEq, Eq, Debug)]
struct Wrap<X>(X);
fn higher_order(_: &()) { }
const CFN: Wrap<fn(&())> = Wrap(higher_order);
fn main() {
check(CFN);
}
fn check<T: Eq + PartialEq + Debug>(something: T) {
println!("{:?}", something);
}
...and it looks like it does implement Eq
and PartialEq
. Am I missing something important here?