Constant items

常量项

constant-items.md
commit: 021889f26215721860a153e692909eda7cfd7a6e
本章译文最后维护日期:2023-05-03

句法
ConstantItem :
   const ( IDENTIFIER | _ ) : Type ( = Expression )? ;

常量项是一个可选的具名 常量值,它与程序中的具体内存位置没有关联。无论常量在哪里使用,它们本质上都是内联的,这意味着当它们被使用时,都是直接被拷贝到相关的上下文中来使用的。这包括使用非拷贝(non-Copy)类型的值和来自外部的 crate 的常量。对相同常量的引用不保证它们引用的是相同的内存地址。

常量必须显式指定数据类型。类型必须具有 'static生存期:程序初始化器(initializer)中的任何引用都必须具有 'static生存期。

常量可以引用其他常量的地址,在这种情况下,如果适用,该地址将具有省略的生存期,否则(在大多数情况下)默认为 'static生存期。(请参阅静态生存期省略。)但是,编译器仍有权多次调整转移该常量,因此引用的地址可能并不固定。

#![allow(unused)]
fn main() {
const BIT1: u32 = 1 << 0;
const BIT2: u32 = 1 << 1;

const BITS: [u32; 2] = [BIT1, BIT2];
const STRING: &'static str = "bitstring";

struct BitsNStrings<'a> {
    mybits: [u32; 2],
    mystring: &'a str,
}

const BITS_N_STRINGS: BitsNStrings<'static> = BitsNStrings {
    mybits: BITS,
    mystring: STRING,
};
}

常量表达式只能在trait定义中省略

Constants with Destructors

常量与析构函数

常量可以包含析构函数。析构函数在值超出作用域时运行。1

#![allow(unused)]
fn main() {
struct TypeWithDestructor(i32);

impl Drop for TypeWithDestructor {
    fn drop(&mut self) {
        println!("Dropped. Held {}.", self.0);
    }
}

const ZERO_WITH_DESTRUCTOR: TypeWithDestructor = TypeWithDestructor(0);

fn create_and_drop_zero_with_destructor() {
    let x = ZERO_WITH_DESTRUCTOR;
    // x 在函数的结尾处通过调用 drop 方法被销毁。
    // 打印出 "Dropped. Held 0.".
}
}

Unnamed constant

未命名常量

不同于关联常量自由常量(free constant)可以使用下划线来命名。例如:

#![allow(unused)]
fn main() {
const _: () =  { struct _SameNameTwice; };

// OK 尽管名称和上面的一样:
const _: () =  { struct _SameNameTwice; };
}

下划线导入一样,宏可以多次安全地在同一作用域中扩展出相同的未具名常量。例如,以下内容不应该产生错误:

#![allow(unused)]
fn main() {
macro_rules! m {
    ($item: item) => { $item $item }
}

m!(const _: () = (););
// 这会展开出:
// const _: () = ();
// const _: () = ();
}

Evaluation

求值

自由常量总是在编译时进行计算,以消除 panics。即使在未使用的函数中也会发生这种情况:

#![allow(unused)]
fn main() {
// Compile-time panic
const PANIC: () = std::unimplemented!();

fn unused_generic_function<T>() {
    // A failing compile-time assertion
    const _: () = assert!(usize::BITS == 0);
}
}
1

在程序退出前,析构销毁的只是其中的一份拷贝;这句还有另一层含义是常量在整个程序结束时会调用析构函数。