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

能否编写Rust宏build_fn生成元组元素?附Bevy实践尝试

实现build_fn宏的需求与解决方案尝试

需求说明

需要编写build_fn宏,实现将指定类型列表与函数列表组合,生成每个函数针对每个类型的具体化版本并嵌入元组。示例如下:

fn foo<T>() { println!("foo: {:?}", std::any::type_name::<T>()); }
let functions = (foo::<i32>, build_fn!(i64,u64,f32,f64;foo), foo::<u32>);

// 最终期望展开为:
let functions = (foo::<i32>, foo::<i64>, foo::<u64>, foo::<f32>, foo::<f64>, foo::<u32>);

// 更复杂场景支持多函数:
// build_fn!(i64,u64,f32,f64;foo,boo)
// 期望展开为 (foo::<i64>, boo::<i64>, foo::<u64>, boo::<u64>, ...)

临时macro_rules方案(基于Bevy ECS实现)

在Bevy开发中,已实现一个可用但略显繁琐的macro_rules方案:

macro_rules! unit_team_system {
    ($($team:ty),* ; $sys:tt) => {
        ($(unit_team_system!(@make_fun $team; $sys),)*)
    };
    (@make_fun $team:ty; ($($sys:ident),* $(,)?) ) =>{
        ($($sys::<$team>,)*)
    };
}

#[derive(Debug)]
struct TeamA;

#[derive(Debug)]
struct TeamB;

#[derive(Debug)]
struct TeamC;

fn system_a<T>() {
    println!("system_a: {:?}", std::any::type_name::<T>());
}

fn system_b<T>() {
    println!("system_b: {:?}", std::any::type_name::<T>());
}

fn main() {
    let systems = unit_team_system!(TeamA, TeamB, TeamC;
               (
                system_a,
                system_b,
                )
        );

    systems.1.0();
}

过程宏(proc_macro)尝试及问题

后续尝试使用过程宏实现,但目前无法正确生成元组子元素,代码如下:

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use syn::{Ident, Token, Type};
use syn::parse::{Parse, ParseStream};


struct UnitTeamSystem {
    teams: Vec<Type>,
    systems: Vec<Ident>,
}

impl Parse for UnitTeamSystem {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let mut teams = Vec::new();
        let mut systems = Vec::new();
        while !input.is_empty() {
            if input.peek(Token![;]) {
                break;
            }
            if input.peek(Token![,]) {
                input.parse::<Token![,]>()?;
            }
            let team: Type = input.parse()?;
            teams.push(team);
        }

        input.parse::<Token![;]>()?;

        while !input.is_empty() {
            let system: Ident = input.parse()?;
            systems.push(system);
            if input.peek(Token![,]) {
                input.parse::<Token![,]>()?;
            }
        }
        Ok(UnitTeamSystem {
            teams,
            systems,
        })
    }
}

#[proc_macro]
pub fn unit_team_system(input: TokenStream) -> TokenStream {
    let UnitTeamSystem { teams, systems } = syn::parse_macro_input!(input as UnitTeamSystem);

    let mut tokens = Vec::with_capacity(teams.len());

    for team in teams {
        for system in &systems {
            tokens.push(quote! {
                #system::<#team>,
            });
        }
    }

    eprintln!("{:?}", tokens);

    TokenStream::from(quote! {
        (#(#tokens)*)
    })
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 01:45:08