#130 May 10, 2026

130. mem::discriminant — Compare Enum Variants, Ignore the Payload

You want to know “is this another Click?” — not whether the coordinates match. Hand-rolling a match for every variant gets old fast. std::mem::discriminant answers that question in one call.

The problem

Say you have an event enum with payload data on every variant:

1
2
3
4
5
6
#[derive(Debug)]
enum Event {
    Click { x: i32, y: i32 },
    KeyPress(char),
    Scroll(i32),
}

Two Clicks with different coordinates are still both clicks. Deriving PartialEq won’t help — that compares the inner data too. The usual workaround is a tedious match:

1
2
3
4
5
6
7
8
fn same_kind_match(a: &Event, b: &Event) -> bool {
    match (a, b) {
        (Event::Click { .. }, Event::Click { .. }) => true,
        (Event::KeyPress(_), Event::KeyPress(_)) => true,
        (Event::Scroll(_), Event::Scroll(_)) => true,
        _ => false,
    }
}

Every new variant means another arm. Forget one and you’ve got a silent bug.

The fix: mem::discriminant

1
2
3
4
5
use std::mem::discriminant;

fn same_kind(a: &Event, b: &Event) -> bool {
    discriminant(a) == discriminant(b)
}

discriminant(&value) returns an opaque Discriminant<T> representing which variant the value is — nothing more. Two Clicks with wildly different coordinates have the same discriminant; a Click and a KeyPress don’t.

No match, no missing-arm bugs, no recompile when you add a new variant.

Bonus: Discriminant<T> is Hash + Eq + Copy

That makes it a perfectly good HashMap key, which is great for counting events by variant without writing a tag enum:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
use std::collections::HashMap;
use std::mem::discriminant;

let events = [
    Event::Click { x: 0, y: 0 },
    Event::KeyPress('a'),
    Event::Click { x: 1, y: 1 },
    Event::Scroll(5),
    Event::KeyPress('b'),
];

let mut counts: HashMap<_, usize> = HashMap::new();
for ev in &events {
    *counts.entry(discriminant(ev)).or_insert(0) += 1;
}
// counts now holds: Click -> 2, KeyPress -> 2, Scroll -> 1

Reach for discriminant whenever you find yourself writing a kind() method or an “is this the same variant?” match. The std lib already has it.

← Previous 128. slice::copy_within — Shift Bytes In-Place Without Fighting the Borrow Checker Next → 129. BTreeMap::extract_if — Range-Scoped Filter-and-Remove in One Pass