How to use Iterator any and all

Use .any() to check if one item matches a condition and .all() to verify every item matches in a Rust iterator.

Checking conditions across a collection

You are writing a game loop. The player walks into a room filled with traps. Before the player moves, the engine needs to check if any trap is triggered. If even one trap is active, the player takes damage. Later, the player collects keys. The door only opens when every key has been found. You need a way to ask the collection: "Is there at least one trap?" and "Are all keys present?"

Rust iterators provide .any() and .all() for exactly this pattern. They take a closure that returns a boolean and scan the iterator to answer your question. The critical detail is that they short-circuit. They stop the moment the answer is determined. This saves work and prevents unnecessary computation.

The short-circuit advantage

any returns true if the closure returns true for at least one item. It returns false only if the iterator is exhausted without finding a match. all returns true if the closure returns true for every item. It returns false the moment the closure returns false for any item.

Think of a line of people. You want to know if anyone is wearing a red hat. You look at the first person. If they have a red hat, you stop. You found your answer. You never look at the rest of the line. That is any.

Now you want to know if everyone is wearing a hat. You look at the first person. If they are bareheaded, you stop. You found your answer. You never look at the rest of the line. That is all.

Short-circuiting matters when the iterator is large or expensive. If you have a million items and the first one satisfies the condition, any returns immediately. You avoid processing the remaining 999,999 items.

fn main() {
    let scores = vec![85, 92, 78, 90, 95];

    // Check if any score is failing.
    // Stops at 78. Never looks at 90 or 95.
    let has_failure = scores.iter().any(|&s| s < 80);

    // Check if all scores are passing.
    // Stops at 78. Never looks at 90 or 95.
    let all_passing = scores.iter().all(|&s| s >= 80);

    println!("Has failure: {}", has_failure);
    println!("All passing: {}", all_passing);
}

Short-circuiting is free performance. Take it.

How the iterator drives the check

Iterators in Rust are lazy. Calling .iter() on a vector does not do any work. It just creates an iterator object. The work happens when you consume the iterator. Methods like any and all are consumers. They pull items from the iterator one by one.

When you call .any(|x| condition), Rust calls next() on the iterator. It gets the first item. It passes that item to your closure. If the closure returns true, any returns true immediately. The iterator is dropped. No more items are fetched. If the closure returns false, any calls next() again. This repeats until true is found or the iterator is exhausted. If exhausted, any returns false.

all works symmetrically. It returns false on the first false from the closure. It returns true only if the iterator runs out without finding a false.

This design means any and all work with any iterator, not just vectors. They work with file lines, network streams, and infinite sequences. The iterator protocol handles the fetching; the method handles the logic.

Infinite iterators and the hang trap

You can use any and all on infinite iterators, but you must understand the risk. If the iterator never ends, the method will run forever unless it short-circuits.

any is safe on an infinite iterator if a match exists. It finds the match and stops. all is dangerous on an infinite iterator. It can only stop if it finds a failure. If every item passes, all runs forever.

use std::iter;

fn main() {
    // An infinite iterator that always yields true.
    let infinite_trues = iter::repeat(true);

    // any short-circuits on the first true. Returns immediately.
    let result = infinite_trues.clone().any(|x| x);
    println!("Any true: {}", result);

    // all checks every item.
    // Since every item is true, it never finds a false.
    // This would hang forever. Uncomment to see the hang.
    // let result = infinite_trues.all(|x| x);
}

Infinite iterators demand short-circuiting. If your predicate never returns true, any runs forever. If your predicate never returns false, all runs forever. Guard infinite streams with a limit or ensure the condition will trigger.

Real-world validation

In application code, you often validate lists of objects. You might check if a user has a specific permission or if all items in a cart are in stock.

#[derive(Debug)]
struct User {
    id: u32,
    role: String,
    email_verified: bool,
}

/// Check if the team has at least one admin.
/// Returns true as soon as an admin is found.
fn has_admin(users: &[User]) -> bool {
    users.iter().any(|u| u.role == "admin")
}

/// Verify all users have confirmed their email.
/// Returns false as soon as an unverified user is found.
fn all_verified(users: &[User]) -> bool {
    users.iter().all(|u| u.email_verified)
}

fn main() {
    let team = vec![
        User { id: 1, role: "dev".to_string(), email_verified: true },
        User { id: 2, role: "admin".to_string(), email_verified: true },
        User { id: 3, role: "dev".to_string(), email_verified: false },
    ];

    println!("Has admin: {}", has_admin(&team));
    println!("All verified: {}", all_verified(&team));
}

Convention aside: when you call .any() or .all() on a slice, use .iter() to get references. This avoids moving the values. If you need ownership, use .into_iter(), but that consumes the collection. The community prefers borrowing unless you explicitly need to take the items.

The empty iterator trap

The most common pitfall with all is the empty iterator. all returns true on an empty iterator. This is called vacuous truth.

Mathematically, "all items in the empty set satisfy condition P" is true because there are no items that violate P. Rust follows this logic. If you check permissions.iter().all(|p| p == "admin") on an empty list, the result is true.

This breaks intuition in security checks. If a user has no permissions, and you check all to see if they have admin rights, you might accidentally grant access.

fn main() {
    let permissions: Vec<&str> = vec![];

    // This is true. There are no non-admin permissions.
    let is_admin = permissions.iter().all(|p| *p == "admin");
    println!("Is admin: {}", is_admin);

    // This is false. There are no admin permissions.
    let has_admin = permissions.iter().any(|p| *p == "admin");
    println!("Has admin: {}", has_admin);
}

If you need to ensure the list is not empty, check the length first. Combine the check with a logical AND.

fn main() {
    let permissions: Vec<&str> = vec![];

    // Require at least one permission, and all must be admin.
    let is_admin = !permissions.is_empty() && permissions.iter().all(|p| *p == "admin");
    println!("Is admin: {}", is_admin);
}

Test the empty case. An empty list passes every all check.

Common compiler errors

Closures in any and all must match the type yielded by the iterator. If the iterator yields references, your closure parameter must accept references.

If you try to move a value out of a reference, the compiler rejects you with E0507 (cannot move out of borrowed content). This happens when you write |item| but the iterator yields &T. The closure tries to take ownership of item, which is a reference. You cannot move the underlying value through a reference.

fn main() {
    let words = vec!["hello".to_string(), "world".to_string()];

    // Error: E0507. words.iter() yields &String.
    // The closure tries to move the String out.
    // let result = words.iter().any(|w| w.len() > 5);

    // Fix: Destructure the reference in the pattern.
    let result = words.iter().any(|w| w.len() > 5);
    // Or use &w to bind the reference explicitly.
    // let result = words.iter().any(|&w| w.len() > 5);
    println!("Result: {}", result);
}

If the closure returns the wrong type, you get E0308 (mismatched types). The closure must return bool. If you accidentally return an Option<bool> or a unit type, the compiler points out the mismatch.

The closure signature must match the iterator yield. Fix the borrow, not the logic.

Convention: find vs any

Developers sometimes use any when they actually need find. any returns a boolean. find returns the first item that matches the predicate.

If you need to know whether an item exists and then process that item, do not call any followed by find. That iterates the collection twice. Use find once. It returns Some(item) if a match exists, or None if not. You can check existence with .is_some() and get the value at the same time.

fn main() {
    let users = vec!["alice", "bob", "charlie"];

    // Bad: Iterates twice.
    // let has_bob = users.iter().any(|u| *u == "bob");
    // if has_bob {
    //     let bob = users.iter().find(|u| **u == "bob");
    // }

    // Good: Iterates once.
    if let Some(bob) = users.iter().find(|u| **u == "bob") {
        println!("Found bob: {}", bob);
    }
}

If you need the value, use find. If you just need the truth, use any.

Decision: when to use any and all

Use any when you need a boolean result and can stop as soon as you find one match. Use all when you need to verify a condition holds for every item and can stop on the first failure. Use find when you need the actual item that matches, not just a boolean. Use a manual for loop when the logic requires complex state tracking across iterations that a simple closure cannot express. Avoid filter().count() > 0 for existence checks. It iterates the entire collection even if the first item matches. Avoid filter().count() == len for universal checks. It also iterates everything. Prefer all for short-circuiting.

If you are using Rayon for parallelism, use par_iter().any() and par_iter().all(). These methods parallelize the check across cores and still short-circuit efficiently. The parallel runtime handles the coordination.

Where to go next