After reading method-call expressions, dereference operator, method lookup, and auto-dereferencing, I thought I had a pretty good understanding of the subject; but then I encountered a situation in which I expected auto-dereferencing to happen, when in fact it didn't happen.
The example is as follows.
#[derive(Clone, Copy, Debug)]
struct Foo();
impl Into<&'static str> for Foo {
fn into(self) -> &'static str {
"<Foo as Into>::into"
}
}
fn vec_into<F: Copy + Into<T>, T>(slice: &[F]) -> Vec<T> {
slice.iter().map(|x| (*x).into()).collect()
}
fn main() {
let array = [Foo(), Foo(), Foo()];
let vec = vec_into::<_, &'static str>(&array);
println!("{:?}", vec);
}
The code above works, but I thought that the explicit dereferencing (*x).into()
in the function vec_into
wasn't needed. My reasoning is that, since x: &Foo
, then x.into()
would try to find methods accepting type &Foo
, &&Foo
, &mut &Foo
, Foo
, &Foo
, &mut Foo
.
This is because there is the chain of dereferencing &Foo
→ Foo
, and for each U
in this chain we insert also &U
and &mut U
.
My intuition is confirmed by the fact that the following code also works, without any explicit dereference.
#[derive(Clone, Copy, Debug)]
struct Foo();
trait MyInto<T> {
fn my_into(self) -> T;
}
impl MyInto<&'static str> for Foo {
fn my_into(self) -> &'static str {
"<Foo as MyInto>::my_into"
}
}
fn vec_my_into<F: Copy + MyInto<T>, T>(slice: &[F]) -> Vec<T> {
slice.iter().map(|x| x.my_into()).collect()
}
fn main() {
let array = [Foo(), Foo(), Foo()];
let my_vec = vec_my_into(&array);
println!("{:?}", my_vec);
}
Here x: &Foo
is implicitly dereferenced in order to call the method <Foo as MyInto<&'static str>>::my_into
.
A smaller example
Given the above definitions of Foo
and MyInto
, the code
let result: &str = (&Foo()).my_into()
works, but
let result: &str = (&Foo()).into()
fails to compile with the error
error[E0277]: the trait bound `&str: std::convert::From<&Foo>` is not satisfied
--> src/bin/into.rs:34:33
|
34 | let result: &str = (&Foo()).into();
| ^^^^ the trait `std::convert::From<&Foo>` is not implemented for `&str`
|
= note: required because of the requirements on the impl of `std::convert::Into<&str>` for `&Foo`