第18章 常量求值

常量求值 — The Rust Reference

译文 · 基于 The Rust Reference

原文链接: https://doc.rust-lang.org/reference/const_eval.html

r[const-eval]

常量求值

r[const-eval.intro] 常量求值是在编译期间计算表达式结果的过程。只有全部表达式的一个子集可以在编译期求值。

r[const-eval.const-expr]

常量表达式

r[const-eval.const-expr.intro] 某些形式的表达式称为常量表达式,可以在编译期求值。

r[const-eval.const-expr.const-context] 常量上下文中的表达式必须是常量表达式。

r[const-eval.const-expr.evaluation] 常量上下文中的表达式总是在编译期求值。

r[const-eval.const-expr.runtime-context] 在常量上下文之外,常量表达式可以在编译期求值,但不保证如此。

r[const-eval.const-expr.error] 诸如越界数组索引或溢出之类的行为,若该值必须在编译期求值(即在常量上下文中),则为编译器错误。否则,这些行为是警告,但很可能在运行时 panic。

r[const-eval.const-expr.list] 下列表达式是常量表达式,只要其任何操作数也是常量表达式,并且不会导致运行任何 Drop::drop 调用。

r[const-eval.const-expr.literal]

r[const-eval.const-expr.parameter]

r[const-eval.const-expr.path-item]

r[const-eval.const-expr.path-static]

  • 指向静态项的路径,带有以下限制:

    • 在任何常量求值上下文中都不允许对 static 项写入。
    • 在任何常量求值上下文中都不允许从 extern 静态项读取。
    • 若求值并非在 static 项的初始化器中进行,则不允许从任何可变 static 读取。可变 static 是 static mut 项,或具有内部可变类型的 static 项。

    这些要求仅在常量被求值时检查。换言之,只要此类访问从未被执行,就允许它们在常量上下文中语法上出现。

r[const-eval.const-expr.tuple]

r[const-eval.const-expr.array]

r[const-eval.const-expr.constructor]

r[const-eval.const-expr.block]

r[const-eval.const-expr.field]

r[const-eval.const-expr.index]

r[const-eval.const-expr.range]

r[const-eval.const-expr.closure]

r[const-eval.const-expr.builtin-arith-logic]

r[const-eval.const-expr.borrows]

  • 所有形式的借用,包括裸借用,但下列情形除外:临时作用域会被延长(见临时生命周期延长)至程序结束,并且该借用是:

    // 由于处于尾部位置,此借用会将该临时值的作用域
    // 延长至程序结束。由于该借用是可变的,
    // 这在常量表达式中是不允许的。
    const C: &u8 = &mut 0; // ERROR not allowed
    
    // Const 块类似于 `const` 项的初始化器。
    let _: &u8 = const { &mut 0 }; // ERROR not allowed
    
    # use core::sync::atomic::AtomicU8;
    // 这是不允许的,因为 1) 临时作用域被延长至
    // 程序结束,且 2) 该临时值具有内部可变性。
    const C: &AtomicU8 = &AtomicU8::new(0); // ERROR not allowed
    
    # use core::sync::atomic::AtomicU8;
    // 同上。
    let _: &_ = const { &AtomicU8::new(0) }; // ERROR not allowed
    
    1
    2
    3
    4
    
    # #![allow(static_mut_refs)]
    // 即便此借用是可变的,它也不是临时值的借用,
    // 因此是允许的。
    const C: &u8 = unsafe { static mut S: u8 = 0; &mut S }; // OK
    
    1
    2
    3
    4
    5
    6
    
    # use core::sync::atomic::AtomicU8;
    // 即便此借用是对具有内部可变性的值的借用,
    // 它也不是临时值的借用,因此是允许的。
    const C: &AtomicU8 = {
        static S: AtomicU8 = AtomicU8::new(0); &S // OK
    };
    
    1
    2
    3
    4
    
    # use core::sync::atomic::AtomicU8;
    // 对内部可变临时值的此共享借用是允许的,
    // 因为其作用域未被延长。
    const C: () = { _ = &AtomicU8::new(0); }; // OK
    
    1
    2
    3
    4
    5
    6
    
    // 即便该借用是可变的,且由于提升该临时值存活至
    // 程序结束,这也是允许的,因为该借用不在尾部位置,
    // 因此临时值的作用域不会经由临时生命周期延长而被延长。
    const C: () = { let _: &'static mut [u8] = &mut []; }; // OK
    //                                              ~~
    //                                     被提升的临时值。
    

r[const-eval.const-expr.deref]

  • 解引用表达式。

    # use core::cell::UnsafeCell;
    const _: u8 = unsafe {
        let x: *mut u8 = &raw mut *&mut 0;
        //                        ^^^^^^^
        //             可变引用的解引用。
        *x = 1; // 可变指针的解引用。
        *(x as *const u8) // 常量指针的解引用。
    };
    const _: u8 = unsafe {
        let x = &UnsafeCell::new(0);
        *x.get() = 1; // 内部可变值的变异。
        *x.get()
    };
    

r[const-eval.const-expr.group]

r[const-eval.const-expr.cast]

  • 强制转换表达式,但下列除外:
    • 指针到地址的强制转换,以及
    • 函数指针到地址的强制转换。

r[const-eval.const-expr.const-fn]

r[const-eval.const-expr.loop]

r[const-eval.const-expr.if-match]

r[const-eval.const-context]

常量上下文

r[const-eval.const-context.def] 常量上下文 是下列之一:

r[const-eval.const-context.array-length]

r[const-eval.const-context.repeat-length]

r[const-eval.const-context.init]

r[const-eval.const-context.generic]

r[const-eval.const-context.block]

r[const-eval.const-context.outer-generics] 数组类型长度表达式、数组重复长度表达式以及常量泛型实参在使用外部泛型参数方面受到限制:此类表达式必须要么是单个常量泛型参数,要么是不引用任何泛型参数的表达式。

r[const-eval.const-fn]

常量函数

r[const-eval.const-fn.intro] 常量函数 是可以从常量上下文调用的函数。它用 const 限定符定义,也包括元组结构体与元组枚举变体构造函数。

r[const-eval.const-fn.const-context] 从常量上下文调用时,常量函数由编译器在编译期解释。解释发生在编译目标的环境中,而非宿主环境。因此,若你针对 32 位系统编译,则 usize 是 32 位,与你是在 64 位还是 32 位系统上构建无关。

r[const-eval.const-fn.outside-context] 当从常量上下文之外调用常量函数时,其行为与没有 const 限定符时相同。

r[const-eval.const-fn.body-restriction] 常量函数的函数体只能使用常量表达式。

r[const-eval.const-fn.async] 不允许常量函数是 async 的。

r[const-eval.const-fn.type-restrictions] 常量函数的参数类型与返回类型受限于与常量上下文兼容的那些类型。

最后修改 August 21, 2026: 更新 (76fc81a2e)