rust - 当Foobar具有正好一个字段时,直接将Vec <Foobar <T >>反序列化为Vec <T>

标签 rust serde

我得到了一种数据格式,其中包括一系列对象,每个对象都有一个命名字段value。反序列化时可以删除此间接层吗?

反序列化时,自然表示为

/// Each record has it's own `{ value: ... }` object
#[derive(serde::Deserialize)]
struct Foobar<T> {
    value: T,
}

/// The naive representation, via `Foobar`...
#[derive(serde::Deserialize)]
struct FoobarContainer {
    values: Vec<Foobar<T>>,
}

尽管Foobar除了T之外没有增加任何额外的成本,但我想在类型级别上删除此间接层:
#[derive(serde::Deserialize)]
struct FoobarContainer {
    values: Vec<T>,
}

可以从Foobar中删除FoobarContainer,同时仍通过反序列化使用它吗?

最佳答案

在一般情况下,没有简单的方法可以进行这种转换。为此,请查看以下现有答案:

  • How do I write a Serde Visitor to convert an array of arrays of strings to a Vec<Vec<f64>>?
  • How to transform fields during deserialization using Serde?

  • 在本示例中,第一个是我的常规入门解决方案和looks like this

    但是,在您的特定情况下,您说:

    objects with exactly one named field value



    您已经确定了一个关键要求:

    While Foobar adds no extra cost beyond T



    这意味着您可以使Foobar具有transparent representation并使用不安全Rust Rust 在类型之间进行转换(尽管not actually with mem::transmute ):
    struct FoobarContainer<T> {
        values: Vec<T>,
    }
    
    #[derive(serde::Deserialize)]
    #[repr(transparent)]
    struct Foobar<T> {
        value: T,
    }
    
    impl<'de, T> serde::Deserialize<'de> for FoobarContainer<T>
    where
        T: serde::Deserialize<'de>,
    {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: serde::Deserializer<'de>,
        {
            let mut v: Vec<Foobar<T>> = serde::Deserialize::deserialize(deserializer)?;
    
            // I copied this from Stack Overflow without reading the surrounding
            // text that describes why this is actually safe.
            let values = unsafe {
                let data = v.as_mut_ptr() as *mut T;
                let len = v.len();
                let cap = v.capacity();
    
                std::mem::forget(v);
    
                Vec::from_raw_parts(data, len, cap)
            };
    
            Ok(FoobarContainer { values })
        }
    }
    

    也可以看看:
  • How do I convert a Vec<T> to a Vec<U> without copying the vector?
  • 关于rust - 当Foobar具有正好一个字段时,直接将Vec <Foobar <T >>反序列化为Vec <T>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62754344/

    相关文章:

    rust - 如何将字符串转换为 &'static str

    json - 使用 serde_json 反序列化 JSON 根数组

    rust - 使用Rust中的Serde从json提升嵌套值可能是可选的

    rust - 在编译时使用 serde_json 反序列化文件

    rust - Rust 如何在 Windows 平台上调用 ufmodlib DLL?

    rust - Rust 教科书的猜谜游戏扩展显示出奇怪的行为

    rust - 如何在 Rust 中编写绑定(bind)到需要打开文件句柄的 C 函数?

    Docker 忽略 `--platform` 中的 `Dockerfile` 标志

    rust - 如何在编译时确保类型将序列化为 JSON 数组?

    json - 从 serde_json 中的非类型化 JSON 中提取数据时如何处理错误?