Shepmaster
Shepmaster

Reputation: 430991

How can I test if a value lies within a Range?

I'd like to be able to create a Range and then test if a variable is contained in that range. Something that looks like this:

fn main() {
    let a = 3..5;
    assert!(a.contains(4));
}

Right now, the only obvious thing I see is to use Iterator::any. This is ugly because it would take an O(1) operation and make it O(n):

fn main() {
    let mut a = 3..5;
    assert!(a.any(|v: i32| v == 4));
}

Upvotes: 46

Views: 42402

Answers (7)

Mint Bee
Mint Bee

Reputation: 49

Before getting into question, you can manifest your code fancier a bit in this way.

fn main() {
    assert!((3..5).contains(&4));
}

Parentheses around 3..5 must used because 3..5.contains($4) is same as 3..(5.contains($4)).

Let's start with why we need & before 4 in contains() method.

contains() method take reference as parameter. You can find It in rust reference -- contains() method in Range struct.

What that means is you are not taking ownership from the parameter of contains(). This method is used to check whether there is the item you are looking for, or not. Therefore, there is no reason for this method should take ownership of the item which is the parameter of contains().

This is why you got compile error and this might be confused at first. Due to ownership and borrowing system of rust, when you are using some functions, you should always consider using literal with reference rather than just put value into the parameter of functions.

Upvotes: -1

Ruben Kostandyan
Ruben Kostandyan

Reputation: 349

You can use match too:

fn main() {
    let v = 132;
    match v {
        1..=100 => println!("Inside"),
        _ => println!("Outside")
    }
}

Upvotes: 14

Andrei Matveiakin
Andrei Matveiakin

Reputation: 1818

This doesn't technically answer your question, but if you want to test that a variable is between two other variables, you could use chain-cmp crate:

use chain_cmp::chmp;

let n = 7;
assert!(chmp!(5 <= n < 10));

The nice thing about chmp! compared to a stand-alone between function is that you naturally see whether range ends are included or excluded.

Upvotes: 1

ASLLOP
ASLLOP

Reputation: 186

You can use my crate cond_utils which allows you to write things like:

if number.between(0, 10) {
    println!("Number is between 0 and 10, limits excluded");
}

or:

if number.within(0, 10) {
    println!("Number is between 0 and 10, limits included");
}

It also has other range comparison methods, for left and right limits, etc.

Upvotes: 0

Allan Chain
Allan Chain

Reputation: 2835

You can also use if let, which is similar to match:

if let 3..=5 = 4 {
    println!("Inside");
}

Also it is easy to assign to a variable:

let s = if let 3..=5 = 4 {
    "Inside"
} else {
    "Outside"
};
println!("{}", s);

Upvotes: 13

Shepmaster
Shepmaster

Reputation: 430991

As of Rust 1.35, the original code will almost1 compile as-is using Range::contains:

fn main() {
    let a = 3..5;
    assert!(a.contains(&4));
}

1 Passing &4 instead of 4 to contains().

Upvotes: 75

Chris Morgan
Chris Morgan

Reputation: 90782

There is nothing on Range itself (at present, anyway), but it is not difficult to do this; after all, it just takes a couple of comparisons:

4 >= a.start && 4 < a.end

Upvotes: 10

Related Questions