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

如何在Rust中复刻C语言struct inheritance可变大小AST节点实现

完全可以复刻该C语言中的struct inheritance实现模式,核心依赖Rust的#[repr(C)]属性强制内存布局符合C规范,具体实现如下:

基础类型定义

首先定义标签枚举和基结构体,和C代码的逻辑完全对应:

// 对应C代码的Ast_Tag,#[repr(u32)]保证枚举内存大小和C的enum一致
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
enum AstTag {
    Ident,
    String,
}

// 对应C代码的Ast基结构体,必须加#[repr(C)]保证字段顺序和C一致
#[repr(C)]
struct Ast {
    tag: AstTag,
    flags: u32,
}

// 示例内部字符串类型,替换为你实际的Intern实现即可
struct Intern;

// 对应C代码的Ast_Ident派生结构体,首字段为基结构体Ast
#[repr(C)]
struct AstIdent {
    base: Ast,
    name: *mut Intern,
}

// 对应C代码的Ast_String派生结构体
#[repr(C)]
struct AstString {
    base: Ast,
    str: *mut Intern,
}

上转(派生类转基类)实现

对应C代码中bar函数的向上转型逻辑,Rust中可直接通过指针转换实现,完全符合C的行为:

// 对应C代码的bar函数
fn bar(ident: *mut AstIdent) {
    // 两种转换方式都合法:
    // 方式1:直接取基字段的指针,逻辑更直观
    let base_node = unsafe { &mut (*ident).base } as *mut Ast;
    // 方式2:直接强转派生指针为基指针,因为#[repr(C)]保证首地址重合
    // let base_node = ident as *mut Ast;
    foo(base_node);
}

下转(基类转派生类)实现

对应C代码中foo函数的向下转型逻辑,和C一致先判断标签再做转换,转换操作需要放在unsafe块中:

// 示例处理函数,替换为实际业务逻辑即可
fn do_something_with_name(val: *mut Intern) {
    // 业务逻辑实现
}

// 对应C代码的foo函数
fn foo(node: *mut Ast) {
    unsafe {
        match (*node).tag {
            AstTag::Ident => {
                let ident_node = node as *mut AstIdent;
                do_something_with_name((*ident_node).name);
            }
            AstTag::String => {
                let str_node = node as *mut AstString;
                do_something_with_name((*str_node).str);
            }
        }
    }
}

关键注意事项

  • 所有涉及继承的结构体必须标注#[repr(C)],Rust默认的内存布局不保证字段顺序,不加该属性会导致指针转换出现未定义行为
  • 上下转型都需要使用unsafe块,类型匹配的校验逻辑需要你自行保证(和C语言的要求完全一致,需要保证tag字段和实际的结构体类型对应)
  • 该方案完全满足不同AST节点内存大小不同的需求,不会出现枚举类型所有变体占用最大内存的问题,1:1复刻了C语言的struct inheritance实现逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 06:54:03