【问题标题】:Implementing Decodable for a wrapper around a fixed size vector为围绕固定大小向量的包装器实现可解码
【发布时间】:2014-08-17 10:09:23
【问题描述】:

背景:序列化板条箱没有记录,派生 Decodable 不起作用。我还查看了其他类型的现有实现,发现代码难以遵循。

解码过程是如何工作的,我如何为这个结构实现 Decodable?

pub struct Grid<A> {
    data: [[A,..GRIDW],..GRIDH]
}

#[deriving(Decodable)] 不起作用的原因是[A,..GRIDW] 没有实现 Decodable,并且当两者都在这个 crate 之外定义时,不可能为一个类型实现一个 trait,这里就是这种情况。所以我能看到的唯一解决方案是手动实现 Decodable for Grid。

这是我所知道的

impl <A: Decodable<D, E>, D: Decoder<E>, E> Decodable<D, E> for Grid<A> {
    fn decode(decoder: &mut D) -> Result<Grid<A>, E> {
        decoder.read_struct("Grid", 1u, ref |d| Ok(Grid {
            data: match d.read_struct_field("data", 0u, ref |d| Decodable::decode(d)) {
                Ok(e) => e,
                Err(e) => return Err(e)
            },
        }))
    }
}

Decodable::decode(d) 出现错误

错误:未能找到 trait 的实现 serialize::serialize::Decodable for [[A, .. 20], .. 20]

【问题讨论】:

  • 最简单的方法往往是“将定义更改为确实有效的东西,使用--pretty expanded 获取该定义,然后进行调整以适应新形式”。
  • @ChrisMorgan 我只是不知道如何将其调整为新形式。
  • @A.B.您要反序列化的 JSON 字符串是什么?
  • github.com/Valve/heliotrope/blob/… - JSON 反序列化的几个例子

标签: serialization rust


【解决方案1】:

由于各种原因,目前还不能很好地做到这一点:

  • 我们不能对固定长度数组的长度进行泛型(基本问题)
  • 当前的 trait coherence 限制意味着我们不能用 impl MyDecodable&lt;D, E&gt; for [A, .. GRIDW](和一个用于 GRIDH)编写自定义 trait MyDecodable&lt;D, E&gt; { ... } 和一揽子实现 impl&lt;A: Decodable&lt;D, E&gt;&gt; MyDecodable&lt;D, E&gt; for A。这会迫使基于 trait 的解决方案使用中间类型,从而使编译器的类型推断非常不愉快,并且 AFAICT 无法满足。
  • 我们没有关联类型(也称为“输出类型”),我认为这可以让类型推断稍微合理。

因此,目前,我们只能手动实现。 :(

extern crate serialize;

use std::default::Default;
use serialize::{Decoder, Decodable};

static GRIDW: uint = 10;
static GRIDH: uint = 5;


fn decode_grid<E, D: Decoder<E>,
               A: Copy + Default + Decodable<D, E>>(d: &mut D) 
        -> Result<Grid<A>, E> {
    // mirror the Vec implementation: try to read a sequence
    d.read_seq(|d, len| {
        // check it's the required length
        if len != GRIDH {
            return Err(
                d.error(format!("expecting length {} but found {}", 
                                GRIDH, len).as_slice()));
        }
        // create the array with empty values ...
        let mut array: [[A, .. GRIDW], .. GRIDH] 
            = [[Default::default(), .. GRIDW], .. GRIDH];

        // ... and fill it in progressively ...
        for (i, outer) in array.mut_iter().enumerate() {
            // ... by reading each outer element ... 
            try!(d.read_seq_elt(i, |d| {
                //  ... as a sequence ...
                d.read_seq(|d, len| {
                    // ... of the right length,
                    if len != GRIDW { return Err(d.error("...")) }

                    // and then read each element of that sequence as the
                    // elements of the grid.
                    for (j, inner) in outer.mut_iter().enumerate() {
                        *inner = try!(d.read_seq_elt(j, Decodable::decode));
                    }
                    Ok(())
                })
            }));
        }

        // all done successfully!
        Ok(Grid { data: array })
    })
}


pub struct Grid<A> {
    data: [[A,..GRIDW],..GRIDH]
}

impl<E, D: Decoder<E>, A: Copy + Default + Decodable<D, E>> 
    Decodable<D, E> for Grid<A> {
    fn decode(d: &mut D) -> Result<Grid<A>, E> {
        d.read_struct("Grid", 1, |d| {
            d.read_struct_field("data", 0, decode_grid)
        })
    }
}

fn main() {}

playpen.

还可以通过使用macros 来实例化每个版本来编写更“通用”的[T, .. n] 解码器,并特别控制如何处理递归解码以允许处理嵌套的固定长度数组(根据需要) Grid);这需要更少的代码(尤其是更多的层,或各种不同的长度),但宏解决方案:

  • 可能更难理解,并且
  • 我给出的那个可能效率较低(为每个固定长度数组创建了一个新的array 变量,包括新的Defaults,而上面的非宏解决方案只使用一个array,因此只为网格中的每个元素调用一次Default::default)。可能可以扩展到一组类似的递归循环,但我不确定。

【讨论】:

  • 感谢您的回答。这可以处理 JSON 吗?这可能是个愚蠢的问题,但 JSON 不需要在尝试读取序列之前读取结构名称和数据字段吗?
  • @A.B.哦,哎呀;我已经计划好了(为什么我有一个单独的功能),但忘记正确实现它。现已修复。
猜你喜欢
  • 1970-01-01
  • 2021-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多