内联 Rust 中的常量值是什么意思?

What does it mean for a constant value in Rust to be inlined?

documentation for const:

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.

我只在 C++ 中见过 "inline functions",但从未内联常量值。对初学者友好的解释是什么?

我也被"no fixed address in memory"搞糊涂了。这是否意味着每次我们使用 const 值时, 堆栈 上的值仅为该表达式分配,并且在表达式执行完毕后,它将是 被摧毁?

A constant 的行为根本不像常规变量;当您定义一个时,它甚至没有自己的范围用于借用检查目的。

比较以下代码生成的MIR:

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

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

你会发现 N 展开后看起来更像是函数而不是变量:

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
    }
}

当它在表达式中使用时,它的值会根据该表达式放在堆栈上,然后立即被遗忘。

编辑:至少这是在 MIR 级别发生的事情。我不是低级优化方面的专家,因此必须在 LLVM 甚至 ASM 中检查实际结果(是否实际使用了堆栈内存)。请注意,这也适用于常规变量。

I've only seen "inline functions" in C++, but never inline constant values.

Rust 中最接近 const 的是 C++ 中的 enum

What is a beginner friendly explanation of how this works?

简单的初学者解释是:它只是工作,不要担心细节。

I'm also confused by "no fixed address in memory". Does that mean every time we use a const value, a value on the stack is allocated just for this expression and after the expression is done executing, it'll be destroyed?

是的。可能是。号

这与罐头上所说的完全相同:不作任何保证。这让编译器有最大的自由来优化事物。


好吧,一切都很好,但是......到底发生了什么?

在实践中,有两种情况:

  • 这个值很简单:它甚至不接触堆栈,而是直接在程序集中硬编码。例如,这最有可能发生在整数上。
  • 值不是那么简单:它是在只读内存中创建的,referenced/copied 从那里开始。堆栈上的多个副本将具有不同的地址。

简单是什么意思?这要看情况。对于每个调用站点,编译器可能会决定是否 "simple enough",这是接近内联的地方。

Does that mean every time we use a const value, a value on the stack is allocated just for this expression and after the expression is done executing, it'll be destroyed?

它不会被摧毁。 const 变量不能具有实现 Drop 的类型。当不再使用时,该值只是被遗忘。如果它曾在堆栈上占用内存,则该内存将在稍后的某个时间被覆盖。

const N: i32 = 5 在 Rust 中就像 #define N 5 在 C 或 C++ 中完成类型安全。

您可以将其视为类型匹配时的文本替换,即 let foo = 32 + N; 相当于您示例中的 let foo = 32 + 5;