
You will not be able to learn anything useful about references from behavior of {:p}
. It's a wrong way to inspect what Rust is doing.
In Rust, objects don't have an identity attached to their address. Objects are movable, so they can exist at different addresses at different times, or not even have any address at all. The same address can be reused for different objects, even within the same function.
&
has a semantic meaning of borrowing, and in many cases it's actually implemented as a pointer, but it doesn't have to be.
Rust is designed around zero-cost abstractions. It's designed to be used with an optimizer, and the optimizer can optimize references out of existence. This happens regularly to local variables and when methods with &
arguments are inlined.
Data that used to be behind a reference can be copied into registers, and registers don't even have an address.
Merely asking about "what's the address of this thing?" changes how the program behaves. It may prevent optimizations that would remove the references from the actual program. It may force data to be copied from registers back to memory just for the purpose of getting some temporary address to print for you, even though that address is useless and not used for any other purpose than printing it.
And it's not just counter-productive with optimizations. In an unoptimized program, you also get nonsense. In the dev/debug builds, Rust only cares about generating code quickly, not about quality of the code. It will create useless temporary variables, it will needlessly move values around. So the same data will have various different addresses that can change, and don't mean much. You're just seeing implementation details, and in the dev/debug mode these aren't even details that anybody pays attention to, because they're all meant to be optimized out of existence in normal release builds.
And finally, Rust has pretty sophisticated auto-dereferencing that peels layers of &
s whenever you call methods on it. In non-edge-case situations when you call (&&&&&p).some_method()
, you're not even using &&&&&p
, and the hypothetical address of the reference-to-reference-to-reference... doesn't matter, because it's dereferenced even before it starts to exist.
{:p}
makes sense in specific cases, such as heap-allocated types and raw pointers, but in many other cases you can get either junk or fiction.