Automatic reference or Ref (?) trait?

I feel I got to the vague area of known unknowns.
I wrote this code for From trait:

impl From<&List> for Vec<u32>{
    fn from(list: &List) -> Vec<u32> { ... }
}

I wrote it because all I need for conversion is immutable reference, which I decided is better, than asking for consuming Self. But now, every call to this from needs reference:

let v:Vec<u32> = (&list).into();

I understand I missed something crucial here, but what? Why Rust does not automatically make ref before calling from &T when it was asked from T?

Dot-autoref, the mechanism you are asking for, only happens if the method solver has found no existing (but not necessarily applicable!) methods that would take a by-value receiver (list in the example).

And it turns out that a method taking a List by value and called .into() does exist, that of the Into<T?> trait: at least for T = List, we do have an impl which is potentially applicable here.

Granted, that choice of T won't work (since you expect to get a T = Vec<u32> on the receiving end (the v)), but you never truly fed T, you instead just relied on (type) inference to provide it. But that happens "too late", by the time the method resolver has decided it's gonna be using list by value, and so at that point it's doomed to realize that there is no choice of T that could satsify both List : Into<T> and T = Vec<u32>.

You could, however, use a helper trait with a distinctly named method to kind of "feed T", in a way:

trait IntoVecU32 : Into<Vec<u32>> {
    /// Feel free to rename it to something shorter.
    fn into_vec_u32 (self)
      -> Vec<u32>
    {
        self.into()
    }
}
impl<T : Into<Vec<u32>>> IntoVecU32 for T {}

let v = list.into_vec_u32(); // OK

More generally, if we consider dot-autoref as a form of inference-induced coercion, the main rule of thumb is that those don't play well with generic functions.

A classic example of this is the reborrowing coercion:

fn takes_mut_ref (_: &mut i32)
{}

fn takes_generic<T> (_: T)
{}

let mut_ref = &mut 42;

takes_mut_ref(mut_ref);
let _ = &*mut_ref; // OK, previous line reborrowed

takes_generic(mut_ref);
let _ = &*mut_ref; // Error, previous line did not reborrow.
4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.