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

如何用Rust递归宏实现泛型Builder的嵌套生成?

Rust 嵌套List Builder递归宏实现方案

问题核心

手动实现的get_builder_bad受限于固定的List嵌套深度,无法适配任意层级结构;递归宏重构时遇到两个关键问题:

  • 宏匹配出现local ambiguity歧义,因规则匹配优先级不明确导致
  • 缺少递归终止分支,无法控制展开深度

解决方案:Incremental TT Muncher模式

采用令牌树啃食器(TT Muncher)模式,通过明确的终止规则和递归优先级解决上述问题,适配任意深度的嵌套List类型。

1. 基础类型与Builder定义(复用已有实现)

#[derive(Debug)]
enum T {
    Int8(i8),
    Int16(i16),
    List(Vec<T>),
}

struct Field {
    name: String,
    ty: T,
}

trait Builder {
    fn build(&self) -> String;
}

struct Int8Builder;
impl Builder for Int8Builder {
    fn build(&self) -> String {
        "Int8Builder".to_string()
    }
}

struct Int16Builder;
impl Builder for Int16Builder {
    fn build(&self) -> String {
        "Int16Builder".to_string()
    }
}

struct ListBuilder<B: Builder>(B);
impl<B: Builder> Builder for ListBuilder<B> {
    fn build(&self) -> String {
        format!("ListBuilder({})", self.0.build())
    }
}

2. 递归宏实现(解决歧义与终止问题)

#[macro_export]
macro_rules! get_builder {
    // 终止规则:优先匹配基础类型,消除歧义
    (Int8) => { Int8Builder };
    (Int16) => { Int16Builder };

    // 递归规则:匹配嵌套List,逐层展开
    (List<$ty:ty>) => {
        ListBuilder(get_builder!($ty))
    };
}

3. 关键问题解决说明

  • 歧义消除:将基础类型的终止规则放在递归规则之前,宏会优先匹配更具体的非List类型,避免List规则与基础类型规则的匹配冲突;同时通过$ty:ty明确类型参数的语法约束,进一步减少模糊匹配。
  • 递归终止:基础类型的规则作为递归终止分支,当宏展开到非List类型时停止递归,返回对应基础Builder,彻底避免无限递归。

4. 使用示例

适配任意深度的嵌套List:

// 生成单层List Builder
let single_list_builder = get_builder!(List<Int8>);
println!("{}", single_list_builder.build()); // 输出:ListBuilder(Int8Builder)

// 生成三层嵌套List Builder
let triple_list_builder = get_builder!(List<List<List<Int16>>>);
println!("{}", triple_list_builder.build()); // 输出:ListBuilder(ListBuilder(ListBuilder(Int16Builder)))

结合Field动态生成Builder:

fn get_builder_for_field(field: &Field) -> Box<dyn Builder> {
    match &field.ty {
        T::Int8(_) => Box::new(get_builder!(Int8)),
        T::Int16(_) => Box::new(get_builder!(Int16)),
        T::List(items) => {
            // 空List默认用Int8Builder,或根据实际需求调整
            let inner_builder = items.first().map_or(
                Box::new(get_builder!(Int8)) as Box<dyn Builder>,
                |item| get_builder_recursive(item)
            );
            Box::new(ListBuilder(*inner_builder))
        }
    }
}

fn get_builder_recursive(ty: &T) -> Box<dyn Builder> {
    match ty {
        T::Int8(_) => Box::new(get_builder!(Int8)),
        T::Int16(_) => Box::new(get_builder!(Int16)),
        T::List(items) => {
            let inner = items.first().map_or(Box::new(get_builder!(Int8)), get_builder_recursive);
            Box::new(ListBuilder(*inner))
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 16:20:14