user1244932
user1244932

Reputation: 8092

Why does iter borrow mutably when used in a pattern guard?

This code:

fn t(r: &[u8]) {
    match r {
        _ if r.iter().any(|&x| x == b';') => {}
        _ => {}
    }
}

gives me the error:

error[E0301]: cannot mutably borrow in a pattern guard
   |
10 |         _ if r.iter().any(|&x| x == b';') => {}
   |              ^^^^^^^^ borrowed mutably in pattern guard

I understand that I can not borrow mutably in match patterns, but why does the compiler think that r.iter() borrows mutably? There is a separate method iter_mut for borrowing mutably.

And how can I check that &[u8] contains b';' without introducing separate functions?

Upvotes: 5

Views: 327

Answers (1)

Shepmaster
Shepmaster

Reputation: 430851

The error message is a bit more nuanced — iter doesn't borrow mutably, but the result of iter is being borrowed mutably. This is because Iterator::any takes self by mutable reference:

fn any<F>(&mut self, f: F) -> bool 
where
    F: FnMut(Self::Item) -> bool, 

Here's a reproduction:

struct X;

impl X {
    fn new() -> X { X } 
    fn predicate(&mut self) -> bool { true }
}

fn main() {
    match () {
        _ if X::new().predicate() => {}
        _ => {}
    }
}

I'd just check if the slice contains the value:

fn t(r: &[u8]) {
    match r {
        _ if r.contains(&b';') => {}
        _ => {}
    }
}

Realistically, this is an example of the borrow checker being overly aggressive. Mutably borrowing something from "outside" the match guard is a bad idea, but mutably borrowing something created in the match guard should be safe.

It's likely that this particular case would work when the borrow checker is rewritten to use Rust's MIR layer.

See also:

Upvotes: 6

Related Questions