Why Universal Function Call is moved( on &mut T), but method call is borrowed?

#1
trait A {
    fn say(self);
}

#[derive(Debug)]
struct B {
    a: i32
}

impl<'a> A for &'a mut B {
    fn say(self) {
        dbg!(self);
    }
}

fn main() {
    let a: &mut Vec<i32> = &mut Vec::new();
    let c = &mut B{a: 23};
    
    c.say(); // is borrowed
    
    A::say(c);  // moved value: `c`
    
    c.say(); // is borrowed
}

playground

#2

say(self) takes ownership of self, i.e. it wants to be the only and the last user of that value ever.

& is copyable, but &mut isn’t implicitly copyable (& is Copy, &mut is Complicated). So when you give &mut to say() you give it exclusive and final access to it.


However, the . operator is magical. If necessary, it takes a reference or runs deref()/deref_mut() on the value before calling the method. You can “re-borrow” &mut to get another one from it temporarily. And that’s what happens with c.say().

use std::ops::DerefMut;
fn main() {
    let mut c = &mut B{a: 23};
    
    c.say(); // is borrowed
    
    A::say(c.deref_mut()); 
    
    c.say(); // is borrowed
}
#3

This is the relevant section of the book

1 Like
#4

thank you

#5

:+1:

#6

The behavior of c.say() is as if you had written the following:

A::say(&mut *c);

This explicit form of reborrowing is sometimes handy to avoid a move.

1 Like