Shared reference to FnMut


#1

This code doesn’t compile:

fn f<F: FnMut()>(mut x: F) {
    x();
}

fn main() {
    let mut x = vec![1];
    let mut y = || x[0] = 2;
    let z = & y;
    f(z);
}

However, the following code does compile:

fn f<F: FnMut()>(mut x: F) {
    x();
}

fn main() {
    let mut x = vec![1];
    let mut y = || x[0] = 2;
    let z = &mut y;
    f(z);
}

Why? One potential explanation is that std::ops has

impl<'a,A,F:?Sized> FnMut<A> for &'a mut F where F : FnMut<A>

but not

impl<'a,A,F:?Sized> FnMut<A> for &'a F where F : FnMut<A>

Is that an omission?


#2

You can’t mutate through a shared reference.


#3

You’ve found the correct cause and no, it’s not an omission. If you would be able to do that, you could modify this code to give you two mutable references to the same location:

#[derive(Clone)]
struct A<'a>(&'a Fn(Option<&'a i32>, A<'a>));

impl<'a> A<'a> {
    fn call(self, p: Option<&'a i32>) {
        self.0(p, self.clone());
    }
}

fn main() {
    let i=3;
    let r=&i;
    let c = move |p,a| {
        if let Some(r2)=p {
            println!("Got two references {:p} & {:p}", r, r2);
        } else {
            A::call(a,Some(r));
        }
    };
    let a=A(&c);
    a.call(None);
}