背景:序列化 crate 未记录,派生的Decodable不起作用。我还查看了其他类型的现有实现,并发现难以理解的代码。

解码过程如何工作,以及如何为此结构实现Decodable?

pub struct Grid<A> {
    data: [[A,..GRIDW],..GRIDH]
}
#[deriving(Decodable)]不起作用的原因是[A,..GRIDW]没有实现Decodable,并且当两个类型都在此 crate 之外定义时,不可能为类型实现特征,在这种情况下就是这种情况。因此,我看到的唯一解决方案是手动实现Grid的Decodable。

而据我所知
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 MyDecodable<D, E> { ... }(对于impl MyDecodable<D, E> for [A, .. GRIDW]使用一个)和一揽子实现GRIDH来编写自定义impl<A: Decodable<D, E>> MyDecodable<D, E> for A。这迫使基于特征的解决方案使用中间类型,这使得编译器的类型推断相当不令人满意,并且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)都创建了一个新的Default变量,而上述非宏解决方案仅使用一个array,因此仅对其中的每个元素调用Default::default一次网格)。可能可以扩展到一组类似的递归循环,但是我不确定。
  • 关于serialization - 为固定大小的向量周围的包装器实现Decodable,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25348218/

    10-13 05:24