Question

Check Whether a Vec Contains a Value in Rust

Question

How can I check whether a value exists in a Rust vector (Vec)? For example, given this vector:

let n = vec!["-i", "mmmm"];

// How can I print "yes" if "-i" is present,
// and "no" otherwise?

Is there a built-in method for this, or do I need to loop through the vector and compare each item manually?

Short Answer

You will learn how to test whether a Vec contains a value in Rust. The main approach is Vec::contains, while iterator methods such as iter().any(...) are useful when you need custom matching rules.

Concept

A Rust vector, written as Vec<T>, stores an ordered collection of values of one type. To determine whether a particular value is stored in that collection, use the built-in contains method.

let n = vec!["-i", "mmmm"];

if n.contains(&"-i") {
    println!("yes");
} else {
    println!("no");
}

contains checks every element until it finds an equal value. It returns a boolean:

  • true when the value is present
  • false when the value is not present

The argument has an & because contains borrows the value being searched for rather than taking ownership of it. This is important in Rust: checking a vector should not consume or destroy either the vector or the search value.

contains works for element types that can be compared for equality, expressed by Rust's PartialEq trait. Common types such as numbers, bool, String, and string slices (&str) support this.

Mental Model

Think of a vector as a row of labeled storage boxes. contains is like asking an assistant: “Is there a box holding this exact item?”

The assistant starts at the first box and compares its contents with the item you requested. If a match is found, the answer is true. If every box has been checked without a match, the answer is false.

You do not have to write that search yourself when an exact equality check is enough—contains already performs it.

Take Quiz

Syntax and Examples

Use contains with a reference to the value you want to find:

let values = vec![10, 20, 30];

if values.contains(&20) {
    println!("20 was found");
}

For a vector of string slices:

let flags = vec!["-i", "--verbose", "--help"];

let has_ignore_case_flag = flags.contains(&"-i");

println!("{has_ignore_case_flag}"); // true

For a vector of owned String values:

let users = vec![String::from("Ada"), String::from("Grace")];
let target = String::from("Ada");

if users.contains(&target) {
    println!("User exists");
}

Use iter().any(...) when the condition is more than exact equality:

let words = vec!["apple", "banana", "pear"];

let has_long_word = words.iter().any(|word| word.len() > 5);

println!("{has_long_word}"); // true, because "banana" has 6 letters

any calls the closure for elements until the closure returns true.

Step by Step Execution

Consider this code:

let n = vec!["-i", "mmmm"];
let found = n.contains(&"-i");

if found {
    println!("yes");
} else {
    println!("no");
}

Execution proceeds as follows:

  1. vec!["-i", "mmmm"] creates a Vec<&str> containing two string slices.
  2. n.contains(&"-i") searches for an element equal to "-i".
  3. contains compares the first element, "-i", with the target.
  4. They are equal, so contains returns true immediately. It does not need to inspect "mmmm".
  5. found stores true.
  6. The if condition is true, so the program prints yes.

If the target were "--debug", Rust would compare it with both entries, find no match, return false, and print no.

Real World Use Cases

Vector membership checks are common when a program has a small or ordered list of values:

  • Command-line flags: Check whether arguments include "--verbose" or "-i".
  • Permissions: Check whether a user's role list contains "admin".
  • Validation: Confirm that a submitted category is one of the allowed categories.
  • Feature toggles: Check whether an enabled-feature list contains a feature name.
  • Game development: Check whether an inventory contains a particular item ID.
  • Data cleanup: Skip records whose status appears in a list of blocked statuses.

For a few values or occasional checks, Vec::contains is simple and appropriate. For many repeated lookups in a large collection, a HashSet is often a better data structure.

Take Quiz

Real Codebase Usage

In production Rust code, contains is often used inside validation and guard clauses.

A guard clause exits early when required data is missing:

fn can_publish(roles: &[String]) -> bool {
    if !roles.contains(&String::from("editor")) {
        return false;
    }

    true
}

When working with Vec<String>, iterators can avoid creating a temporary String for comparisons with a string literal:

fn can_publish(roles: &[String]) -> bool {
    roles.iter().any(|role| role == "editor")
}

Developers also use any for normalized or partial checks:

let blocked_domains = vec!["spam.example", "invalid.example"];
let email = "person@spam.example";

let is_blocked = blocked_domains
    .iter()
    .any(|domain| email.ends_with(domain));

Choose contains when you need exact membership. Choose any when matching requires a rule, transformation, or multiple conditions.

Common Mistakes

Using Python-style in syntax

Rust does not support value in vector.

// This is not valid Rust.
if "-i" in n {
    println!("yes");
}

Use contains instead:

if n.contains(&"-i") {
    println!("yes");
}

Forgetting the reference

contains expects a reference to the target value.

let values = vec![1, 2, 3];

// Does not compile.
// values.contains(2);

Correct code:

assert!(values.contains(&2));

Comparing String values awkwardly

This works, but creates a new String only to search:

let names = vec![String::from("Ada")];
let exists = names.contains(&String::from("Ada"));

For a string literal, an iterator comparison is often clearer:

let exists = names.iter().any(|name| name == "Ada");

Expecting case-insensitive matching

contains performs an exact equality comparison. "Admin" and "admin" are different strings.

let roles = vec!["Admin"];
assert!(!roles.contains(&"admin"));

Use a custom iterator condition when case should not matter:

let has_admin = roles.iter().any(|role| role.eq_ignore_ascii_case("admin"));

Using a vector for many frequent lookups

contains searches from the start and can inspect every element. If you repeatedly check membership in a large, unique collection, consider HashSet instead.

Comparisons

NeedBest toolWhy
Check for one exact value in a Vecvalues.contains(&target)Short and readable
Check a custom condition`values.iter().any(value
Find the matching value itself`values.iter().find(value
Keep only matching values`values.iter().filter(value
Perform many membership checksHashSet::contains(&target)Usually faster lookup than scanning a vector

contains and any can both answer “does a match exist?”:

let values = vec![1, 2, 3];

assert!(values.contains(&2));
assert!(values.iter().any(|value| *value == 2));

Prefer contains for exact equality. It communicates your intent directly.

Take Quiz

Cheat Sheet

// Exact membership in Vec<T>
let values = vec![1, 2, 3];
let exists = values.contains(&2); // true

// String slices: Vec<&str>
let flags = vec!["-i", "--help"];
let exists = flags.contains(&"-i"); // true

// Custom predicate
let values = vec![1, 2, 3];
let has_even = values.iter().any(|value| value % 2 == 0); // true

// Get the first matching element
let found = values.iter().find(|value| **value == 2); // Some(&2)
  • contains returns bool.
  • Pass the target by reference: contains(&target).
  • contains performs exact equality matching.
  • contains stops once it finds a match.
  • Use iter().any(...) for custom matching logic.
  • For many lookups in a large collection, evaluate whether HashSet<T> fits better.

FAQ

How do I check whether a Rust vector contains a value?

Call contains and pass a reference to the target:

let values = vec![1, 2, 3];
assert!(values.contains(&2));

Why does contains need & in Rust?

contains borrows the target value for comparison. The & creates a reference, allowing Rust to compare the value without moving ownership.

Does Vec::contains return the matching item?

No. It returns only true or false. Use iter().find(...) if you need the matching element:

let found = vec![1, 2, 3].iter().find(|value| **value == 2);

Can I use contains with Vec<String> and a &str?

Vec::contains expects a reference to the vector's element type, so with Vec<String> it naturally accepts &String. For convenient comparisons to a &str, use:

names.iter().any(|name| name == "Ada")

Is contains case-sensitive for strings?

Yes. It uses exact equality. "YES" and "yes" do not match.

Does contains change the vector?

No. It only borrows the vector and searches it. The vector remains available afterward.

When should I use a HashSet instead of a Vec?

Use a HashSet when membership checks are frequent and the collection is large or represents unique values. Keep a Vec when ordering matters, duplicates are meaningful, or the collection is small.

Take Quiz

Mini Project

Description

Build a small command-line flag checker. The program receives a fixed list of arguments and reports whether common flags were supplied. This mirrors a common task in command-line tools before they process files or make network requests.

Goal

Use Vec::contains to detect exact command-line flags and print the selected program settings.

Requirements

  1. Create a vector containing at least three command-line-style flags.
  2. Check whether the vector contains "-i".
  3. Check whether the vector contains "--verbose".
  4. Print a clear message for each enabled or disabled setting.
  5. Use contains rather than writing a manual loop.
Take Quiz

Keep learning

Related questions

View more