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

如何在Rust的不同结构体定义中添加公共字段?

为Rust结构体通过自定义属性宏添加公共字段

需求背景

现有两个Rust结构体定义:

#[derive(Default, Serialize, Deserialize)]
pub struct User {
    pub id: String,
    pub username: String,
    #[serde(rename(serialize = "accountGroupId", deserialize = "accountGroupId"))]
    pub account_group_id: String,
}

#[derive(Default, Serialize, Deserialize)]
pub struct Client {
    pub id: String,
    pub contact: String,
}

需要为这两个结构体添加enable公共字段,实现直接通过user.enable、client.enable访问的使用方式:

let user = User {
    id: "user-id-value".to_string(),
    enable: true,
    ..Default::default()
};

let client = Client {
    id: "client-id-value".to_string(),
    enable: true,
    ..Default::default()
};

要求:

  • 不使用trait(无法直接字段访问)
  • 不使用嵌套字段(避免user.base.enable这类层级访问)
  • 通过自定义属性宏#[user_base]实现自动添加公共字段

实现方案

要实现这个需求,需要基于Rust的**过程宏(proc-macro)**编写自定义属性宏,具体步骤如下:

1. 创建过程宏 crate

新建一个proc-macro类型的crate(比如命名为base_fields_macro),在Cargo.toml中配置:

[package]
name = "base_fields_macro"
version = "0.1.0"
edition = "2021"

[lib]
proc-macro = true

[dependencies]
syn = { version = "2.0", features = ["full", "extra-traits"] }
quote = "1.0"

2. 实现#[user_base]属性宏

在src/lib.rs中编写宏逻辑,解析输入的结构体AST并插入enable字段:

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput, Fields};

#[proc_macro_attribute]
pub fn user_base(_attr: TokenStream, input: TokenStream) -> TokenStream {
    // 解析输入的结构体定义
    let mut input = parse_macro_input!(input as DeriveInput);

    // 仅支持带命名字段的结构体
    if let syn::Data::Struct(ref mut data_struct) = input.data {
        match &mut data_struct.fields {
            Fields::Named(fields_named) => {
                // 插入enable字段,添加serde默认值处理
                let enable_field = syn::parse_quote! {
                    #[serde(default)]
                    pub enable: bool,
                };
                fields_named.named.push(enable_field);
            }
            Fields::Unnamed(_) | Fields::Unit => {
                panic!("#[user_base] only supports structs with named fields");
            }
        }
    } else {
        panic!("#[user_base] can only be applied to structs");
    }

    // 生成修改后的结构体代码
    let expanded = quote! {
        #input
    };

    expanded.into()
}

3. 在主项目中使用宏

在主项目的Cargo.toml中引入过程宏依赖:

[dependencies]
base_fields_macro = { path = "./base_fields_macro" }
serde = { version = "1.0", features = ["derive"] }

给目标结构体添加#[user_base]属性即可:

use base_fields_macro::user_base;
use serde::{Deserialize, Serialize};

#[user_base]
#[derive(Default, Serialize, Deserialize)]
pub struct User {
    pub id: String,
    pub username: String,
    #[serde(rename(serialize = "accountGroupId", deserialize = "accountGroupId"))]
    pub account_group_id: String,
}

#[user_base]
#[derive(Default, Serialize, Deserialize)]
pub struct Client {
    pub id: String,
    pub contact: String,
}

fn main() {
    let user = User {
        id: "user-id-value".to_string(),
        enable: true,
        ..Default::default()
    };

    let client = Client {
        id: "client-id-value".to_string(),
        enable: true,
        ..Default::default()
    };

    println!("User enable status: {}", user.enable);
    println!("Client enable status: {}", client.enable);
}

说明

  • 宏会自动在结构体的命名字段中插入pub enable: bool字段,并添加#[serde(default)]确保反序列化时缺失该字段会使用默认值false
  • 由于结构体派生了Default,创建实例时可以通过..Default::default()补全未指定的字段,包括enable的默认值false
  • 该宏仅支持带命名字段的结构体,若应用于其他类型会触发编译 panic

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 00:34:59