5

The following program works fine:

pub fn foo(_v: &str) -> bool {
    false
}

fn main() {
    let f = "hello world";
    println!("{}", foo(&&&&f)); // note the number of & here
}

In fact it works on passing any number of &. How should I interpret what is going on ?

My rust version:

$ rustc --version
rustc 1.32.0-nightly (13dab66a6 2018-11-05)
trent
  • 25,033
  • 7
  • 51
  • 90
Sibi
  • 47,472
  • 16
  • 95
  • 163
  • Also TRPL says this: `When the Deref trait is defined for the types involved, Rust will analyze the types and use Deref::deref as many times as necessary to get a reference to match the parameter’s type.` – halfelf Nov 14 '18 at 07:59
  • 3
    I don't think the duplicate target is appropriate. That question is about auto-dereferencing (which only happens for a method receiver); this question is about `Deref` coercion (which can happen at any coercion site). – trent Nov 14 '18 at 14:15
  • I think that `autoderef` applies also in the `function(&&&&&x)` case, not only in the context of methods receivers. In this case I could agree with tagging this question as duplicate, but @trentcl expresses another point of view. Some more consideration for helping to clarify? – attdona Nov 16 '18 at 07:16

2 Answers2

5

From the Rust book:

Deref coercion is a convenience that Rust performs on arguments to functions and methods. Deref coercion converts a reference to a type that implements Deref into a reference to a type that Deref can convert the original type into. Deref coercion happens automatically when we pass a reference to a particular type’s value as an argument to a function or method that doesn’t match the parameter type in the function or method definition. A sequence of calls to the deref method converts the type we provided into the type the parameter needs.

So basically, in function arguments the compiler will automatically remove any & written or implied until it gets to a type that can be passed to the function.

Jmb
  • 18,893
  • 2
  • 28
  • 55
5

Because the compiler automatically dereferences the chain of references, you can imagine that it inserts as many * as necessary to get the right type:

foo(&&&f)

is converted to:

foo(&****(&&&f))

that leads to the right invocation:

foo(f)

The insertions of as many * as needed is actually performed by this blanket implementation of Deref trait:

impl<'a, T: ?Sized> Deref for &'a T {
    type Target = T;

    fn deref(&self) -> &T { *self }
}

Note: I've update my answer because in the original I used the term autoderef in the wrong way, see this post for details.

trent
  • 25,033
  • 7
  • 51
  • 90
attdona
  • 17,196
  • 7
  • 49
  • 60