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
相关产品推荐
相关产品推荐

