When can double ampersand && be shortend to a single &

Viewed 103

In pattern matching, one can append &[&] [mut] to an identifier like &e in v.iter().filter(|&e| ...). This is called reference patterns.

When playing with this pattern, I found an inconsistent behavior:

  • For a doubly borrowed value, &&e works but &e also works.

  • When mutable, however, &&mut e works whilst &mut e doesn't work.

Why?

fn main() {

    let mut v = vec![1, 2, 3, 4, 5];

    v.iter()
        .filter(|e| *e * 2 >= 8)
        .for_each(|e| println!("{}", e)); //=> 4 5

    v.iter()
        .filter(|e| **e * 2 >= 8)
        .for_each(|e| println!("{}", e));

    v.iter()
        .filter(|&e| e * 2 >= 8)
        .for_each(|e| println!("{}", e));

    v.iter()
        .filter(|&&e| e * 2 >= 8)
        .for_each(|e| println!("{}", e));

    //NG
    // v.iter_mut()
    //     .filter(|&mut e| e * 2 >= 8)
    //     .for_each(|e| println!("{}", e));

    v.iter_mut()
        .filter(|&&mut e| e * 2 >= 8)
        .for_each(|e| println!("{}", e));

}

Rust Playground

2 Answers

From a high level perspective:

&mut T is a mutable reference of type T and &&mut T is a immutable reference of &mut T.

From a compiler perspective: (ref)

The grammar production for reference patterns has to match the token && to match a reference to a reference because it is a token by itself, not two & tokens.

Adding the mut keyword dereferences a mutable reference

Basically && points the immutable reference to a immutable reference if there is a mut, it dereferences to a mutable reference (immutable ref to mutable ref, i.e. as mentioned above).


  • When mutable, however, &&mut e works whilst &mut e doesn't work.

&mut e doesn't work because method filter from std::iter expects you to define a closure with immutable referenced parameter:

fn filter<P>(self, predicate: P) -> Filter<Self, P>
where
    P: FnMut(&Self::Item) -> bool, 

&&mut T pattern works because Self::Item is a &mut T since you are using iter_mut().

Rust Complier says : you can borrow multiple immutable references, but you cannot borrow multiple mutable references in a defined scope.


let e = 23;

here we can borrow multiple immutable references of &e or reference of reference &&e and our code will not break, because compiler knows all the references are immutable, hence no one can change the value.

but, lets say we borrow a mutable reference of a reference &&mut e , here the problem is we have two mutable references of same object(I: &mut e, II: &&mut e) anyone can change the value of e, and as per rule we are not allowed to have two mutable references of same object in scope.

P.S. Please correct me if i'm wrong.

Related