You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust中如何在const上下文调用非const函数并实现编译时计算?

在Rust const上下文中调用第三方非const函数的可行方案

当你需要在const上下文里调用第三方库的非const函数(且确认相同参数返回结果稳定),可以通过以下两种编译时执行的方式实现:

1. 使用build.rs构建脚本

构建脚本会在编译前运行,执行非const代码计算结果,将结果生成为Rust常量代码,供主程序引用。

实现步骤

  • 在项目根目录创建build.rs,编写代码调用目标函数并生成常量定义
  • 主程序中通过include!引入生成的常量文件

示例代码

build.rs

use bevy_math::primitives::dim2::RegularPolygon;
use bevy_math::Vec2;
use std::fs::File;
use std::io::Write;
use std::path::Path;

fn main() {
    // 编译时执行非const方法计算顶点
    let poly = RegularPolygon::new(7.0, 6);
    let points = poly.vertices(0.0).collect::<Vec<Vec2>>();

    // 将顶点序列化为Rust字面量
    const CODE_TEMPLATE: &str = "pub const MY_VERTICES: &[Vec2] = &[{POINTS}];";
    let point_literals = points
        .iter()
        .map(|v| format!("Vec2::new({}, {})", v.x, v.y))
        .collect::<Vec<_>>()
        .join(", ");
    let generated_code = CODE_TEMPLATE.replace("{POINTS}", &point_literals);

    // 将代码写入编译输出目录的文件
    let out_dir = std::env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("generated_vertices.rs");
    let mut file = File::create(dest_path).expect("Failed to create generated file");
    file.write_all(generated_code.as_bytes())
        .expect("Failed to write generated code");

    // 确保build.rs变更时重新运行脚本
    println!("cargo:rerun-if-changed=build.rs");
}

主程序代码

// 引入编译时生成的常量
include!(concat!(env!("OUT_DIR"), "/generated_vertices.rs"));

const fn my_vertices() -> Vec<Vec2> {
    // 在const函数中将静态数组转为Vec(Rust 1.64+支持)
    MY_VERTICES.to_vec()
}

2. 使用过程宏(Proc Macro)

过程宏允许在编译阶段执行Rust代码,并将计算结果直接嵌入到生成的语法树中,适合需要动态参数的场景。

实现步骤

  • 创建一个proc-macro类型的子 crate
  • 编写过程宏,在宏展开时调用目标非const函数,生成常量表达式

示例代码

proc-macro crate的Cargo.toml

[package]
name = "vertex-gen-macro"
version = "0.1.0"
edition = "2021"

[lib]
proc-macro = true

[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = "2.0"
bevy_math = "0.11" # 匹配主项目的bevy版本

proc-macro源码(src/lib.rs)

use proc_macro::TokenStream;
use quote::quote;

#[proc_macro]
pub fn generate_vertices(_input: TokenStream) -> TokenStream {
    // 编译时执行非const方法
    let poly = bevy_math::primitives::dim2::RegularPolygon::new(7.0, 6);
    let points = poly.vertices(0.0).collect::<Vec<bevy_math::Vec2>>();

    // 生成顶点的字面量表达式
    let point_exprs = points.iter().map(|v| {
        quote! { bevy_math::Vec2::new(#(v.x), #(v.y)) }
    });

    // 生成最终的const代码
    let expanded = quote! {
        {
            const VERTICES: &[bevy_math::Vec2] = &[#(#point_exprs),*];
            VERTICES.to_vec()
        }
    };

    expanded.into()
}

主程序中使用宏

use vertex_gen_macro::generate_vertices;

const fn my_vertices() -> Vec<bevy_math::Vec2> {
    generate_vertices!()
}

注意事项

  • 两种方案均依赖第三方函数结果的稳定性:若第三方函数后续变更行为,必须重新编译才能更新常量值
  • 浮点数计算需注意精度:编译时和运行时的浮点数计算结果可能存在微小差异,需确认是否影响业务逻辑
  • Vec在const函数中的初始化依赖Rust版本(1.64+支持&[T].to_vec()的const调用)

内容的提问来源于stack exchange,提问作者lucidbrot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 14:17:13