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

Rust中如何将结构体字段设置为固定常量值减少内存分配

实现方法

核心思路很简单:固定值完全没必要用堆分配的String存储,更没必要每个实例都存一份,直接利用Rust静态字符串+serde的配置就能做到零额外重复分配。


方案1:最小改动,保留字段访问能力

把字段类型从String换成&'static str静态字符串切片,配合serde的默认值配置,所有实例共享全局唯一的常量字符串,完全没有堆分配开销。
代码实现:

use serde::{Serialize, Deserialize};

// 全局常量,编译期写入二进制只读段,全程序仅存一份
const PRICE_MSG_TYPE: &str = "price";

#[derive(Serialize, Deserialize, Debug, Default)]
pub struct PriceMessage {
    // 这里放你其他需要动态存储的业务字段即可
    // 例:pub price: f64,
    // 例:pub symbol: String,

    // 配置序列化字段名、默认值
    #[serde(rename = "message_type", default = "fixed_msg_type")]
    pub message_type: &'static str,
}

// 返回固定静态值,无任何内存分配
fn fixed_msg_type() -> &'static str {
    PRICE_MSG_TYPE
}

使用时不需要手动给message_type赋值,直接走默认值即可:

let msg = PriceMessage {
    // 其他业务字段赋值
    // price: 100.5,
    // symbol: "BTC_USDT".into(),
    ..Default::default()
};

这个方案的优势:

  • 你可以正常在代码中通过msg.message_type访问字段值
  • 字段本身只是一个指向静态内存的指针(64位系统下占8字节),比String(24字节)省2/3内存,创建时不需要做任何堆拷贝
  • 序列化时会正常输出"message_type": "price"字段,和你之前用String的序列化结果完全一致
  • 如果需要反序列化时忽略传入的message_type值、强制用固定值,给字段加#[serde(skip_deserializing)]属性即可;如果需要校验传入值必须为"price",自定义一个校验函数就行。

方案2:极致零开销,完全不存储该字段

如果你连8字节的字段内存都不想占,直接自定义序列化/反序列化逻辑,结构体里完全不定义message_type字段,序列化时自动写入固定键值对,反序列化时自动跳过该字段解析。
代码实现:

use serde::{Serialize, Serializer, Deserialize, Deserializer};
use serde::ser::SerializeStruct;

const PRICE_MSG_TYPE: &str = "price";

#[derive(Debug, Default)]
pub struct PriceMessage {
    // 仅存储需要动态变化的业务字段
    // 例:pub price: f64
}

impl Serialize for PriceMessage {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        // 第二个参数填结构体总字段数:动态字段数 + 1个固定message_type字段
        let mut state = serializer.serialize_struct("PriceMessage", 1)?;
        // 写入固定字段,直接引用静态常量,无分配
        state.serialize_field("message_type", PRICE_MSG_TYPE)?;
        // 写入其他业务字段,例:state.serialize_field("price", &self.price)?;
        state.end()
    }
}

impl<'de> Deserialize<'de> for PriceMessage {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        // 可自行实现字段解析逻辑,跳过message_type字段,仅解析业务字段
        // 简单场景也可以通过辅助结构体+serde派生实现,不用手写trait
        Ok(Self::default())
    }
}

这个方案下结构体的内存大小完全等于你业务字段的大小,没有任何额外开销,适合对内存占用、实例创建速度要求极高的高频场景。


注意事项

绝对不要用String存这类固定值:String的内存分配在堆上,每次创建实例都要拷贝一份字符串到堆,频繁创建时会带来大量不必要的分配、释放开销,性能差还浪费内存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 05:27:13