What does it mean for a const type in Rust to be i

2019-05-01 07:09发布

问题:

I'm an absolute beginner to Rust and systems programming in general. The documentation for const in Rust says this :

Constants live for the entire lifetime of a program. More specifically, constants in Rust have no fixed address in memory. This is because they’re effectively inlined to each place that they’re used. References to the same constant are not necessarily guaranteed to refer to the same memory address for this reason.

I've only came across inline functions in C++, but never inline const types. Can someone please provide a beginner friendly explanation of how this works?

Also, I'm a bit confused with no fixed address in memory. Does that mean every time we used the const type, a value in the stack is allocated just for this expression and after the expression is done executed, it'll be destroyed?

回答1:

I've only came across inline functions in C++, but never inline const types.

The closest approximate to a const in Rust is an enum in C++.

Can someone please provide a beginner friendly explanation of how this works?

The simple beginner's explanation is: it just works, don't worry about the nitty gritty details.

Also, I'm a bit confused with no fixed address in memory. Does that mean every time we used the const type, a value in the stack is allocated just for this expression and after the expression is done executed, it'll be destroyed?

Yes. Maybe. No.

It means exactly what it says on the tin: no guarantee is made. This leaves the compiler with the maximum freedom to optimize things.


Alright, that's all good and well, but... what really happens?

In practice, there are two situations:

  • the value is simple enough: it does not even touch the stack, and instead is hardcoded directly in the assembly. This is most likely to happen for integrals, for example.
  • the value is not that simple: it is created in read-only memory, and referenced/copied from there. Multiple copies on the stack will obviously have different addresses.

What does simple mean? Well, it depends. For each call site the compiler may decide "simple enough" or not, which is where it is close to inlining.

Does that mean every time we used the const type, a value in the stack is allocated just for this expression and after the expression is done executed, it'll be destroyed?

It will not be destroyed. const variables cannot have a type that implements Drop. The value is just forgotten when it is no longer in used. And if ever occupied memory on the stack, this memory will be overwritten sometimes later.



回答2:

const N: i32 = 5 in Rust is like #define N 5 in C or C++ done with type-safety.

You can think of it like a textual substitution when the type matches, that is, let foo = 32 + N; is equivalent to let foo = 32 + 5; in your example.



回答3:

A constant doesn't behave like a regular variable at all; when you define one it doesn't even get its own scope for borrow-checking purposes.

Compare the MIR generated by the following pieces of code:

fn main() {
    const N: i32 = 5;
}

and

fn main() {
    let n: i32 = 5;
}

And you will find that what N expands to looks more like a function than a variable:

const main::N: i32 = {
    let mut _0: i32;                     // return pointer

    bb0: {
        _0 = const 5i32;                 // scope 0 at <anon>:2:20: 2:21
        return;                          // scope 0 at <anon>:2:5: 2:22
    }
}

When it is used in an expression, its value is placed on the stack for the purpose of that expression and is forgotten right afterwards.

Edit: at least this is what happens on MIR level. I'm not an expert on low-level optimizations, so the actual outcome (whether stack memory was actually used) would have to be checked in LLVM or even ASM. Note that this is also applicable to regular variables, though.