Question about &T and Deref trait

Since all &T implements the Deref trait by default, why can't I automatically dereference to match i32 in this code, but require me to explicitly dereference?

fn main() {
    let i: i32 = 1;
    let j = &i;
    let k = test(j);
    println!("{}", k);
}

fn test(a: i32) -> i32 {
    a + 1
}

Explicit dereferencing is needed sometimes in Rust, it is not always automatic. The dereferencing you're expecting -- to dereference a variable of type &T when passing it as a function parameter of type T -- is not one of the things that is done automatically.

Or are you asking: why isn't it automatic?

1 Like

As documented here (in the two bullet points mentioning Deref and DerefMut), the kind of dereferencing used in implicit coercions (which is the only kind of "automatic dereference" applicable in function arguments) only supports cases where you're turning a reference to some type to a refetence to the target / result of referencing it.

Concretely, for &T: Deref<Target = T>, this means that &&T can implicitly turn into &T, for example &&i32 into &i32, but not &i32 into i32 - that only works with explicit dereferencing, using the prefix * operator.

5 Likes

I seem to understand a little bit. It is precisely because str cannot be used directly. The smallest unit of use is &str, so related types related to it can be automatically dereferenced.

Yes, I previously thought this should be automatic.

Not just str, but also all !Copy types — you can't go from a &T to a T in the general case.

Rust could have had an additional coercion rule that &T can be coerced to T when T: Copy, but it doesn't.

3 Likes

There is one case where a function argument is automatically dereferenced in this way: When you use method call syntax j.test(), the compiler will reference or dereference the receiver j as many times as necessary to find the appropriate method.

For example:

fn main() {
    let i: i32 = 1;
    let j = &i;
    let k = j.test();
    println!("{}", k);
}


trait MyTrait {
    fn test(self) -> Self;
}

impl MyTrait for i32 {
    fn test(self: i32) -> i32 { self + 1 }
}
2 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.