Published on

Rust编译时与运行时代码:核心特征与实用指南

1. 编译时代码的特征

形式典型场景判断依据
const 常量/函数const PI: f32 = 3.14;使用 const 关键字
static 静态变量static CONFIG: &str = "config";不可变全局变量
属性宏#[derive(Debug)]#[...] 开头
过程宏serde::Serialize生成代码的宏
泛型参数fn<T> foo() {}类型在编译时确定
const _: () = ...编译时断言无名常量包裹的表达式
include_str! 等宏文件内嵌! 结尾的宏

2. 运行时代码的特征

形式典型场景
fn 普通函数fn main() { println!(); }
let 绑定let x = 1 + 1; (非常量上下文)
match/if流程控制
trait 动态分发dyn Trait
Box/Vec堆分配
网络/文件 I/Ostd::fs::read

3. 快速判断技巧

  1. 看关键字

    • const/static → 编译时
    • fn/let → 运行时(除非在 const fn 中)
  2. 看宏调用

    • 属性宏(#[...])→ 编译时
    • 普通宏(println!)→ 运行时展开
  3. 看错误发生时机

    • 编译错误 → 编译时问题
    • panic/逻辑错误 → 运行时问题
  4. 看是否依赖输入

    • 需要用户输入/网络 → 必定运行时
    • 纯计算 → 可能编译时优化

4. 典型示例对比

// 编译时执行
const SQUARE: fn(i32) -> i32 = |x| x * x;  // 常量函数指针
const _: () = assert!(SQUARE(2) == 4);      // 编译时断言

// 运行时执行
fn main() {
    let input = 3;                          // 运行时绑定
    println!("{}", SQUARE(input));           // 运行时计算
}

5. 特殊情况

  • const fn:可在编译时和运行时调用
const fn add(a: i32, b: i32) -> i32 { a + b }
const SUM: i32 = add(1, 2);  // 编译时执行
let sum = add(3, 4);         // 运行时执行
  • lazy_static:运行时初始化,但仅一次
// lazy_static运行时初始化
lazy_static! {
    static ref CONFIG: HashMap<String, String> = {
        let mut m = HashMap::new();
        m.insert("key".into(), "value".into());
        m
    };
}
  • const generics:编译时确定的泛型参数(如 [i32; N]
// 编译期泛型
fn generic_fn<T: Default>() -> T {
    T::default()  // 具体类型在编译时确定
}

6. agave code example

// Ensure the STORE_META_OVERHEAD constant remains accurate
const _: () = assert!(
    STORE_META_OVERHEAD
        == mem::size_of::<StoredMeta>()
            + mem::size_of::<AccountMeta>()
            + mem::size_of::<AccountHash>()
);

7. 实践

    1. 内存优化技巧
// 利用编译时布局优化Cache Line
#[repr(align(64))] // 强制缓存行对齐
struct CriticalData {
    hot: [u64; 8],    // 高频访问
    cold: [u128; 4]    // 低频数据
}

const _: () = assert!(std::mem::size_of::<CriticalData>() == 256);
    1. 错误处理模式
// 编译时错误码生成
macro_rules! define_errors {
    ($($code:ident => $msg:literal),*) => {
        pub mod errors {
            $(
                pub const $code: (&str, u32) = ($msg, line!());
            )*
        }
    };
}

define_errors! {
    OVERFLOW => "Arithmetic overflow",
    UNAUTHORIZED => "Permission denied"
}
    1. 零成本抽象
// 编译时策略选择
trait Backend {
    const IS_GPU: bool;
    fn compute() -> u64;
}

struct CpuBackend;
impl Backend for CpuBackend {
    const IS_GPU: bool = false;
    fn compute() -> u64 { /* CPU优化实现 */ }
}

// 根据特性选择算法
const fn select_algo<B: Backend>() -> fn() -> u64 {
    if B::IS_GPU { gpu_kernel } else { cpu_kernel }
}
    1. 混合使用
// 可在编译时和运行时调用的函数
const fn factorial(n: u32) -> u32 {
    match n {
        0 | 1 => 1,
        _ => n * factorial(n - 1),
    }
}

fn main() {
    const COMPILE_TIME: u32 = factorial(5);  // 编译时计算
    let runtime = factorial(10);             // 运行时计算
}

THE END