rustmemoryreference

What is the memory representation of Rust types with multiple ampersands?


The Rust book gives a representation of a reference to an owned type, and it looks like this:enter image description here

My question is, what does it look like in memory when multiple references are "stacked"? For example: let y = &&someString;

Were there only a single ampersand, it would be easy to understand using the picture above, but with two or more ampersands, I get confused. There is no intermediate value to point to, so how does Rust represent this in memory?

There is something similar with let x = &5. Since x stores the reference to 5, where does 5 live?

I am not necessarily looking for a when and how to use these specific cases, I am only curious about what is happening under the hood when these kinds of things happen.

Looked through the rust book and other websites to no avail.


Solution

  • The memory representation is exactly as you'd expect. A reference is a pointer which "points" to the referenced type by storing its address. And because references are also first-class types in Rust, a &&T is a pointer to a pointer to a T - there is no funny business going on.

    So the question is: where does that intermediate reference live? If everything was spelled out explicitly, then there is no question:

    let s: String = ...;
    let ref_s: &String = &s;
    let ref_ref_s: &&String = &ref_s;
    

    However if you do it in one line:

    let s: String = ...;
    let ref_ref_s: &&String = &&s;
    

    due to temporary lifetime extension, the compiler treats it as-if you had done the first:

    let s: String = ...;
    let _tmp: &String = &s;
    let ref_ref_s: &&String = &_tmp;
    

    And this can nest allowing let ... = &&&... to work as well. NOTE: this formulation is specific to let, it doesn't work with assignments for example.

    So where are the intermediate references? They are in the local scope where you defined your variable.

    In other situations like passing &&&T to a function: some_func(&&&some_param), the idea is the same but scope is only valid until that expression is done. See temporary scopes for other sites and behaviors.


    The let x = &5 is technically a bit different since 5 is a constant and can be promoted. Essentially the 5 gets embedded into your program's static memory and so x is simply a 'static reference that points to it.