在自定义序列化器中复制 serde(with) 的行为

问题描述 投票:0回答:1

我写了一个自定义的

chrono::DateTime<Utc>
序列化器:

pub mod datetime {
    pub fn serialize<S: Serializer>(
        date: &DateTime<Utc>,
        serializer: S,
    ) -> Result<S::Ok, S::Error> {
        // ...
    }

    // deserialize omitted
}

我需要为

struct
实现自定义序列化逻辑,并且在将
serde(with = "datetime")
的行为模拟为结构体字段上的属性时遇到困难。我想要复制的内容:

#[derive(Serialize, Deserialize)]
struct Foo {
    #[serde(with = "datetime")]
    pub timestamp: DateTime<Utc>,
}

我的尝试:

impl Serialize for Foo {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        let mut m = serializer.serialize_map(None)?;
        m.serialize_entry(
            "timestamp",
            &datetime::serialize(&self.timestamp, serializer)?,
        )?;
        m.end()
    }
}

导致错误:

error[E0277]: the trait bound `<S as foo::_::_serde::Serializer>::Ok: Serialize` is not satisfied
    --> <...>/foo.rs:95:13
     |
93   |         m.serialize_entry(
     |           --------------- required by a bound introduced by this call
94   |             "timestamp",
95   |             &datetime::serialize(&self.sent_timestamp, serializer)?,
     |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Serialize` is not implemented for `<S as foo::_::_serde::Serializer>::Ok`
     |
note: required by a bound in `serialize_entry`
    --> ~/.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.193/src/ser/mod.rs:1808:12
     |
1801 |     fn serialize_entry<K: ?Sized, V: ?Sized>(
     |        --------------- required by a bound in this associated function
...
1808 |         V: Serialize,
     |            ^^^^^^^^^ required by this bound in `SerializeMap::serialize_entry`
help: consider further restricting the associated type
     |
86   |     fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> where <S as foo::_::_serde::Serializer>::Ok: Serialize {
     |

我是否误解了

Serializer
的用法?我不完全确定我在这里做错了什么。

rust serialization serde
1个回答
0
投票

正如评论中所建议的,使用

#[derive(Serialize)]
查看
#[serde(with)]
的扩展将帮助我们了解派生代码到底在做什么,从而使我们能够复制其行为。这可以通过将代码复制到 Rust Playground 并使用“工具”下拉菜单中的“扩展宏”选项来完成。

在查看扩展的代码时,我们看到如下所示的内容(尽管我已经对其进行了重大清理以使其更具可读性):

struct SerializeWith<'a>(&'a DateTime<Utc>);

impl Serialize for SerializeWith<'_> {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        datetime::serialize(&self.0, serializer)
    }
}

因此,正确的方法是定义一个直接调用自定义序列化逻辑的新类型。完整正确的

Serialize
实现是:

impl Serialize for Foo {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        struct SerializeWith<'a>(&'a DateTime<Utc>);

        impl Serialize for SerializeWith<'_> {
            fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
                datetime::serialize(&self.0, serializer)
            }
        }

        let mut m = serializer.serialize_struct("Foo", 1)?;

        m.serialize_field("timestamp", &SerializeWith(&self.timestamp))?;

        m.end()
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.