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

如何为Rust结构体实现Serde的Deserialize trait?

解决方法

优先使用自动派生(推荐)

serde提供了#[derive(Deserialize)]宏,能自动为结构体生成Deserialize实现,这比手动实现简单且不易出错,是日常开发的首选方案。

步骤1:修改Cargo.toml

需要启用serde的derive特性,同时为了处理Duration的反序列化,我们额外引入serde_with工具库:

serde = { version = "1.0.140", features = ["derive"] }
serde_with = "3.0"

步骤2:为结构体添加派生宏

标准库的std::time::Duration默认没有实现Deserialize,我们用serde_with的适配器将其转换为可序列化的原始类型(比如u64,代表纳秒数,可根据你的数据格式调整):

use serde::Deserialize;
use std::time::Duration;
use serde_with::serde_as;

#[serde_as]
#[derive(Deserialize)]
pub struct Transaction {
    pub sender: String,
    pub receiver: String,
    pub amount: f64,
    pub signature: String,
    pub status: &'static str,
    pub weight: u128,
    #[serde_as(as = "u64")]
    pub timestamp: Duration,
    pub edges: Vec<Transaction>,
}

如果不想引入额外依赖,也可以把timestamp字段改成u64类型,在业务逻辑中再转换为Duration,或者手动为Duration实现Deserialize。


手动实现Deserialize trait(仅作学习参考)

如果你一定要手动实现,需要修复代码中的错误并编写对应的Visitor逻辑:

修复后的完整代码

use serde::de::{Deserialize, Deserializer, Visitor, MapAccess};
use std::fmt;
use std::time::Duration;

pub struct Transaction {
    pub sender: String,
    pub receiver: String,
    pub amount: f64,
    pub signature: String,
    pub status: &'static str,
    pub weight: u128,
    pub timestamp: Duration,
    pub edges: Vec<Transaction>,
}

// 自定义Visitor,负责解析结构体的键值对
struct TransactionVisitor;

impl<'de> Visitor<'de> for TransactionVisitor {
    type Value = Transaction;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("a Transaction struct")
    }

    fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
    where
        M: MapAccess<'de>,
    {
        let mut sender = None;
        let mut receiver = None;
        let mut amount = None;
        let mut signature = None;
        let mut status = None;
        let mut weight = None;
        let mut timestamp = None;
        let mut edges = None;

        // 遍历所有键值对
        while let Some(key) = map.next_key()? {
            match key {
                "sender" => sender = Some(map.next_value()?),
                "receiver" => receiver = Some(map.next_value()?),
                "amount" => amount = Some(map.next_value()?),
                "signature" => signature = Some(map.next_value()?),
                "status" => status = Some(map.next_value()?),
                "weight" => weight = Some(map.next_value()?),
                "timestamp" => {
                    // 假设timestamp以纳秒数的u64形式序列化
                    let nanos: u64 = map.next_value()?;
                    timestamp = Some(Duration::from_nanos(nanos));
                }
                "edges" => edges = Some(map.next_value()?),
                // 忽略未知字段,也可以返回错误
                _ => { map.next_value::<serde::de::IgnoredAny>()?; }
            }
        }

        // 校验必填字段并返回结构体实例
        Ok(Transaction {
            sender: sender.ok_or_else(|| serde::de::Error::missing_field("sender"))?,
            receiver: receiver.ok_or_else(|| serde::de::Error::missing_field("receiver"))?,
            amount: amount.ok_or_else(|| serde::de::Error::missing_field("amount"))?,
            signature: signature.ok_or_else(|| serde::de::Error::missing_field("signature"))?,
            status: status.ok_or_else(|| serde::de::Error::missing_field("status"))?,
            weight: weight.ok_or_else(|| serde::de::Error::missing_field("weight"))?,
            timestamp: timestamp.ok_or_else(|| serde::de::Error::missing_field("timestamp"))?,
            edges: edges.unwrap_or_default(),
        })
    }
}

// 实现Deserialize trait
impl<'de> Deserialize<'de> for Transaction {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_struct(
            "Transaction",
            &["sender", "receiver", "amount", "signature", "status", "weight", "timestamp", "edges"],
            TransactionVisitor,
        )
    }
}

你代码中的错误说明

  1. 生命周期未声明:impl Deserialize<'de> for Transaction 需要先在impl后声明生命周期参数,即impl<'de> Deserialize<'de> for Transaction。
  2. 类型参数D未定义:deserialize方法的D需要作为方法的类型参数声明,即fn deserialize<D>(deserializer: D) ...,而非单独在方法上声明'de。
  3. 缺少Visitor实例:deserialize_struct必须传入一个实现了Visitor trait的实例,不能传None,你需要自定义Visitor来处理结构体字段的解析逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 17:57:19