Alternatives to matching floating point ranges
I would personally do this:
#[derive(Debug, PartialEq)]
enum Color {
Red,
Yellow,
Blue,
Grey,
}
trait InRange {
fn in_range(self, begin: Self, end: Self) -> bool;
}
impl InRange for f32 {
fn in_range(self, begin: f32, end: f32) -> bool {
self >= begin && self < end
}
}
impl From<f32> for Color {
fn from(f: f32) -> Color {
match f {
x if x.in_range(0.0, 0.1) => Color::Red,
x if x.in_range(0.1, 0.4) => Color::Yellow,
x if x.in_range(0.4, 0.8) => Color::Blue,
_ => Color::Grey,
}
}
}
fn main() {
assert_eq!(Color::from(0.2), Color::Yellow);
}
Since Rust 1.35, the InRange
functionality implemented by Boiethios is already provided in the contains
method on Range<f32>
:
impl From<f32> for Color {
fn from(f: f32) -> Color {
match f {
x if (0.0..0.1).contains(&x) => Color::Red,
x if (0.1..0.4).contains(&x) => Color::Yellow,
x if (0.4..0.8).contains(&x) => Color::Blue,
_ => Color::Grey,
}
}
}
However, I would tend to write this with only one comparison against each number, which reduces the chance of typos introducing bugs:
impl From<f32> for Color {
fn from(f: f32) -> Color {
match f {
x if x < 0.0 => Color::Grey;
x if x < 0.1 => Color::Red,
x if x < 0.4 => Color::Yellow,
x if x < 0.8 => Color::Blue,
_ => Color::Grey,
}
}
}
This style also makes it more obvious that there are two disjoint ranges that return Color::Grey
: x < 0.0
and x >= 0.8
.
See also
- How can I test if a value lies within a Range?