编程自动化,嵌入式和系统开发者

解释一下 Rust 中常量表达式(const expressions)是如何工作的,它们何时被计算,并给出一个实际使用的例子,在编译时编译器计算出值。

用 Hintsage AI 助手通过面试

在 Rust 中,常量表达式(const)在编译阶段计算,使得在程序运行之前创建的值成为程序的一部分。这种表达式用于指定数组的大小、静态结构中的值、泛型参数以及其他需要具有固定已知值的不变常量的情况。

在 Rust 中,可以创建“常量”函数(const fn),可以在其他常量表达式中使用或用于初始化常量变量。编译器保证此表达式不包含不允许的操作(例如,内存访问)。

示例:

const fn fib(n: u32) -> u32 { match n { 0 | 1 => 1, _ => fib(n - 1) + fib(n - 2), } } const F8: u32 = fib(8); const ARR: [u32; F8 as usize] = [0; F8 as usize]; // 数组大小为 34

在此示例中,值 F8 和数组 ARR 的大小在编译阶段计算。

难题

const函数与普通函数有什么区别?是否可以将任何函数声明为 const fn

回答: 不,并不是所有函数都可以声明为 const fnconst fn 只能包含允许的操作,不允许有副作用或不安全的内存操作。例如,不能在 const fn 中打开文件或动态分配内存。

const fn add(x: i32, y: i32) -> i32 { x + y // 合法 } // 这个不会编译: const fn fail() -> String { // 错误! String::from("err") }

由于对主题细节的不了解而导致的实际错误示例


故事

在一个项目中,试图通过常量函数在编译阶段计算字符串的哈希值,但在此函数内使用了 HashMap 中的标准方法和内存分配。程序无法编译,抛出了关于在 const fn 中不允许操作的无法理解的错误。


故事

在大型嵌入式开发中,开发者定义了一个需要在编译阶段计算的字段的常量结构,但在初始化中使用了未标记为 const fn 的外部 crate 的函数。这导致无法使用该逻辑来确定静态缓冲区的大小。


故事

在代码中混淆了 staticconst 的区别,试图在执行时修改“常量”,并得到了隐式的 UB(未定义行为),因为在 Rust 中,常量并不像值那样存储在内存中,而是由编译器在使用位置进行替换,这根本不意味着他们可以被修改。