Into() behaves differently in form of `Into::<T>::into(x)` and `x.into()`

Code:

use std::convert::From;

#[derive(Debug)]
struct FromType {
    v: ToType,
}

#[derive(Debug)]
struct ToType {
}

impl<'a> From<&'a mut FromType> for &'a mut ToType {
    fn from(f: &'a mut FromType) -> &'a mut ToType {
        &mut f.v
    }
}

struct Wrapper<'a> {
    inner: &'a mut FromType,
}

impl<'a> Wrapper<'a> {
    fn dump(self) -> Self {
        // The line below errors compiler that self.inner is partially moved.
        // let from = Into::<&mut ToType>::into(self.inner);

        // This is ok
        let from: &mut FromType = self.inner.into();
        dbg!(from);
        self
    }
}

fn main() {
    let from = &mut FromType { v: ToType {} };
    let wrapper = Wrapper { inner: from };
    let _wrapper = wrapper.dump();

    println!("Hello, world!");
}

In the dump() method of Wrapper struct, Into::<&mut ToType>::into(self.inner) and self.inner.into() make compiler behaving differently.

Calling the into() method by Into::<T>::into(x) consumes the value totally. However, x.into() does not.

self.inner.into() in this case is not Into::into(self.inner), but rather Into::into(&mut *self.inner), i.e. the value is implicitly reborrowed. With this modification, code compiles successfully - playground.

3 Likes

Thank you @Cerber-Ursi, you really help a lot.