#178 Jun 2, 2026

178. Ord::clamp — Stop Writing min(max, max(min, x))

Bounding a value between two limits is one of those tiny operations where everyone hand-rolls a confusing nest of min/max calls. Ord::clamp is the single-call version, and it works on anything that’s Ord or PartialOrd — not just numbers.

You’ve seen this somewhere in every codebase:

1
2
let volume = raw.max(0).min(100);          // OK
let other  = std::cmp::min(100, std::cmp::max(0, raw)); // worse

Both work. Both make you stop and squint to figure out which bound is which. clamp says exactly what it does:

1
let volume = raw.clamp(0, 100);

It’s defined for Ord on integers, and as f32::clamp / f64::clamp for floats (which need PartialOrd because of NaN). Same shape on all of them:

1
2
3
4
5
6
assert_eq!((-5_i32).clamp(0, 10), 0);
assert_eq!(7_i32.clamp(0, 10), 7);
assert_eq!(99_i32.clamp(0, 10), 10);

assert_eq!(2.5_f64.clamp(0.0, 1.0), 1.0);
assert_eq!((-0.3_f64).clamp(0.0, 1.0), 0.0);

It’s not just for numbers. Anything Ord works — char, &str, String, your own types:

1
2
assert_eq!('z'.clamp('a', 'f'), 'f');
assert_eq!("zebra".clamp("apple", "mango"), "mango");

One gotcha: clamp panics if min > max. That’s deliberate — a backwards range is almost always a bug, and silently returning either bound would hide it. If your bounds come from user input or config, validate them once at the boundary:

1
2
3
4
5
6
fn safe_clamp(x: i32, lo: i32, hi: i32) -> i32 {
    let (lo, hi) = if lo <= hi { (lo, hi) } else { (hi, lo) };
    x.clamp(lo, hi)
}

assert_eq!(safe_clamp(5, 10, 0), 5); // bounds got swapped, still works

For floats there’s one more wrinkle: f64::clamp propagates NaN if the input is NaN, but panics if either bound is NaN. So x.clamp(0.0, 1.0) is safe as long as your bounds are real numbers — which they always should be.

← Previous 177. BTreeMap::range — Iterate a Sorted Map by Key Range Next → 179. Iterator::max_by_key — Find the Best Element Without a Manual Fold