Skip to content

Rust - 常量

常量是绑定到一个名称且不允许更改的值。在 Rust 中,常量使用 const 关键字声明,并且它们的类型必须始终被注解(annotated)。

const MAX_POINTS: u32 = 100_000;

常量的命名约定是使用所有大写字母,单词之间用下划线分隔(SCREAMING_SNAKE_CASE)。常量可以在任何作用域中声明,包括全局作用域,这使得它们对于程序多个部分共享的值非常有用。

const SECONDS_IN_MINUTE: u32 = 60;
const MINUTES_IN_HOUR: u32 = 60;
const SECONDS_IN_HOUR: u32 = SECONDS_IN_MINUTE * MINUTES_IN_HOUR;
fn main() {
println!("There are {} seconds in an hour.", SECONDS_IN_HOUR);
}
There are 3600 seconds in an hour.

你可能会想,既然 Rust 默认就有不可变变量(let),为什么还需要常量呢?虽然它们看起来相似,但存在重要的区别:

  • 类型注解:你必须注解 const 的类型。而 let 通常可选,因为编译器可以推断它。
  • 可变性:const 值永远不能通过 mut 变为可变。虽然 let 绑定默认是不可变的,但它们可以用 mut 标记。
  • 评估时间:const 必须设置为一个常量表达式,即编译器在编译时可以确定的值。它不能是函数调用或任何在运行时计算的值的结果。
  • 内联:const 值在代码中使用的地方实际上会被内联。这意味着 const 没有单个内存地址。
  • 作用域:const 可以在任何作用域中声明,包括全局。let 仅限于函数或块作用域。
fn get_runtime_value() -> u32 {
// 某些复杂计算...
5
}
fn main() {
// 这有效:该值在编译时计算。
const COMPILE_TIME_VALUE: u32 = 5 * 2;
// 这无效:该值在运行时计算。
// const RUNTIME_VALUE: u32 = get_runtime_value(); // 错误:常量中的函数调用仅限于常量函数
// 不可变变量适用于运行时值。
let runtime_variable = get_runtime_value();
println!("Compile-time: {}, Runtime: {}", COMPILE_TIME_VALUE, runtime_variable);
}

Rust 还有另一种创建在程序整个生命周期内都存在的值的方式:static 变量。与 const 不同,static 变量有一个固定的内存位置。static 变量也可以是可变的(使用 static mut),但访问或修改可变 static 变量是 unsafe(不安全)的,因为它可能引入数据竞争(data races)。对于永不改变的值,const 几乎总是更好的选择。

static HELLO_WORLD: &str = "Hello, world!";
fn main() {
println!("Static says: {}", HELLO_WORLD);
}

与用 let 声明的变量不同,常量不能被遮蔽(shadowed)。尝试在同一作用域中声明同名的另一个常量将导致编译时错误。

fn main() {
const NAME: &str = "Alice";
// 下面这行代码会导致编译错误:
// const NAME: usize = 0; // error[E0260]: 名称 `NAME` 已多次定义
println!("Name is {}", NAME);
}