2

According to my understanding, next needs a &mut Test, but create_test() returns a Test.

Why can this be compiled?

My guess is that . will implicitly convert Test to &mut Test, I am not sure. Can somebody explain more about this?

pub struct Test {
    t: u64,
}

fn create_test() -> Test {
    Test {
        t: 1
    }
} 

impl Test {
    pub fn next(&mut self) {
        self.t = 10;
    }
}

fn main() {
    let mut t = Test { t: 20 };
    t.next();

    create_test().next();  // here
}
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 1
    Until it's assigned to a non-`mut` variable it's considered mutable. The type only really gets locked down when you store it somewhere. – tadman Feb 02 '23 at 01:45
  • Indeed, `.` will coerce `T` into `&T` or `&mut T` as needed. This is special behavior of `.`. A manual method call `Test::next(t);` does not do this and requires an explicit `&mut t`. – John Kugelman Feb 02 '23 at 01:50
  • 1
    When calling `.` on something the action taken depends entirely on the function itself. Some take `self`, some `&self`, `&mut self` or what have you, where the compiler determines how to handle that. In other cases it has to be `Deref` first. This is only possible if there's no limitations, as in stored in a non-`mut` variable, which would then generate an error. – tadman Feb 02 '23 at 01:50

1 Answers1

1

This is explained in the Method-call expressions section of the book.

When looking up a method call, the receiver may be automatically dereferenced or borrowed in order to call a method.

This is exactly what is happening here. The rust compiler is automatically borrowing value returned create_test.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
pigeonhands
  • 3,066
  • 15
  • 26