Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

rust

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?

like image 600
user1244932 Avatar asked Jul 08 '17 14:07

user1244932


Video Answer


1 Answers

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:

  • Rust issue #24535
like image 150
Shepmaster Avatar answered Sep 17 '22 23:09

Shepmaster