我有以下格式的JSON对象:

{
  "name": "foo",
  "value": 1234,
  "upper_bound": 5000,
  "lower_bound": 1000
}

我想使用serde来处理这些对象

struct MyObject {
  name: String,
  value: i32,
  bound: Range<i32>,
}

在没有任何修改的情况下,序列化其中一个 struct 会产生

{
  "name": "foo",
  "value": 1234,
  "bound": {
    "start": 1000,
    "end": 5000
  }
}

我可以申请#[serde(flatten)]英镑来拉近距离

{
  "name": "foo",
  "value": 1234,
  "start": 1000,
  "end": 5000
}

但是,添加#[serde(rename...)]似乎并没有改变任何事情,无论我try 给重命名提供什么样的参数.是否可以展平范围并重命名参数?

推荐答案

您可以使用serde属性with,只需使用一个中间 struct ,让真正的实现进行serde:

use core::ops::Range;
use serde::{Deserialize, Serialize};
use serde_json::Error;

#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
struct Foo {
    name: String,
    value: i32,
    #[serde(with = "range_aux", flatten)]
    bound: Range<i32>,
}

mod range_aux {
    use core::ops::Range;
    use serde::{Deserialize, Deserializer, Serialize, Serializer};

    #[derive(Serialize, Deserialize)]
    struct RangeAux {
        upper_bound: i32,
        lower_bound: i32,
    }

    pub fn serialize<S>(range: &Range<i32>, ser: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        RangeAux::serialize(
            &RangeAux {
                upper_bound: range.end,
                lower_bound: range.start,
            },
            ser,
        )
    }

    pub fn deserialize<'de, D>(d: D) -> Result<Range<i32>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let range_aux: RangeAux = RangeAux::deserialize(d)?;
        Ok(Range {
            start: range_aux.lower_bound,
            end: range_aux.upper_bound,
        })
    }
}

fn main() -> Result<(), Error> {
    let data = r#"{"name":"foo","value":1234,"upper_bound":5000,"lower_bound":1000}"#;

    let foo: Foo = serde_json::from_str(data)?;

    assert_eq!(
        foo,
        Foo {
            name: "foo".to_string(),
            value: 1234,
            bound: 1000..5000
        }
    );

    let output = serde_json::to_string(&foo)?;

    assert_eq!(data, output);

    Ok(())
}

这非常接近remote个模式,但这不适用于泛型请参见serde#1844.

可能的通用版本:

use core::ops::Range;
use serde::{Deserialize, Serialize};
use serde_json::Error;

#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
struct Foo {
    name: String,
    value: i32,
    #[serde(with = "range_aux", flatten)]
    bound: Range<i32>,
}

mod range_aux {
    use core::ops::Range;
    use serde::{Deserialize, Deserializer, Serialize, Serializer};

    pub fn serialize<S, Idx: Serialize>(range: &Range<Idx>, ser: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        // could require Idx to be Copy or Clone instead of borrowing Idx
        #[derive(Serialize)]
        struct RangeAux<'a, Idx> {
            upper_bound: &'a Idx,
            lower_bound: &'a Idx,
        }
        RangeAux::serialize(
            &RangeAux {
                upper_bound: &range.end,
                lower_bound: &range.start,
            },
            ser,
        )
    }

    pub fn deserialize<'de, D, Idx: Deserialize<'de>>(d: D) -> Result<Range<Idx>, D::Error>
    where
        D: Deserializer<'de>,
    {
        #[derive(Deserialize)]
        struct RangeAux<Idx> {
            upper_bound: Idx,
            lower_bound: Idx,
        }
        let range_aux: RangeAux<Idx> = RangeAux::deserialize(d)?;
        Ok(Range {
            start: range_aux.lower_bound,
            end: range_aux.upper_bound,
        })
    }
}

fn main() -> Result<(), Error> {
    let data = r#"{"name":"foo","value":1234,"upper_bound":5000,"lower_bound":1000}"#;

    let foo: Foo = serde_json::from_str(data)?;

    assert_eq!(
        foo,
        Foo {
            name: "foo".to_string(),
            value: 1234,
            bound: 1000..5000
        }
    );

    let output = serde_json::to_string(&foo)?;

    assert_eq!(data, output);

    Ok(())
}

Rust相关问答推荐

为什么我们不能通过指针算法将Rust原始指针指向任意地址?'

如何在Rust中获得不可辩驳的'if let'模式警告Mutex锁定?""

如何将元素添加到向量并返回对该元素的引用?

在Rust中,有没有一种方法让我定义两个 struct ,其中两个都遵循标准 struct ?

Rust:跨多个线程使用hashmap Arc和rwlock

使用Clap时如何将String作为Into Str参数传递?

当对VEC;U8>;使用serde_json时,Base64编码是保护空间的好方法吗?

Rust移动/复制涉及实际复制时进行检测

如何从宏调用闭包?

Rust,如何从 Rc> 复制内部值并返回它?

借来的价值生命周期 不够长,不确定为什么它仍然是借来的

相当于 Rust 中 C++ 的 std::istringstream

将多维数组转换为切片

使用 traits 时,borrow 的值不会存在足够长的时间

rust 中不同类型的工厂函数

如何在 Rust 中将 UTF-8 十六进制值转换为 char?

如何在 Rust 中返回通用 struct

Abortable:悬而未决的期货?

制作嵌套迭代器的迭代器

为什么 Bevy 的 Trait 边界不满足 Rapier 物理插件?