2017-02-22 82 views
8

我想要做的结构序列化,其中的字节最终将被发送到一个管道,重建和调用方法。如何反序列化为特征,而不是具体类型?

我创建了一个特点,这些结构将实施适当的和我使用SERDE和SERDE-CBOR序列化:

extern crate serde_cbor; 
#[macro_use] 
extern crate serde_derive; 
extern crate serde; 

use serde_cbor::ser::*; 
use serde_cbor::de::*; 

trait Contract { 
    fn do_something(&self); 
} 

#[derive(Debug, Serialize, Deserialize)] 
struct Foo { 
    x: u32, 
    y: u32, 
} 

#[derive(Debug, Serialize, Deserialize)] 
struct Bar { 
    data: Vec<Foo>, 
} 

#[derive(Debug, Serialize, Deserialize)] 
struct Baz { 
    data: Vec<Foo>, 
    tag: String, 
} 

impl Contract for Bar { 
    fn do_something(&self) { 
     println!("I'm a Bar and this is my data {:?}", self.data); 
    } 
} 

impl Contract for Baz { 
    fn do_something(&self) { 
     println!("I'm Baz {} and this is my data {:?}", self.tag, self.data); 
    } 
} 

fn main() { 
    let data = Bar { data: vec![Foo { x: 1, y: 2 }, Foo { x: 3, y: 4 }, Foo { x: 7, y: 8 }] }; 
    data.do_something(); 

    let value = to_vec(&data).unwrap(); 
    let res: Result<Contract, _> = from_reader(&value[..]); 
    let res = res.unwrap(); 
    println!("{:?}", res); 
    res.do_something(); 
} 

当我试图重建使用特征作为类型字节(假设我不知道哪个基础对象被发送),编译器会抱怨的特质没有实现Sized特点:

error[E0277]: the trait bound `Contract: std::marker::Sized` is not satisfied 
    --> src/main.rs:52:15 
    | 
52 |  let res: Result<Contract, _> = from_reader(&value[..]); 
    |    ^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Sized` is not implemented for `Contract` 
    | 
    = note: `Contract` does not have a constant size known at compile-time 
    = note: required by `std::result::Result` 

我想这是有道理的,因为编译器不知道结构应该有多大,不知道如何排列它的字节。如果我改线,我反序列化对象指定实际的结构类型,它的工作原理:

let res: Result<Bar, _> = from_reader(&value[..]); 

有没有更好的方式来实现这一系列化+多态行为?

+2

我......不认为你能做到这一点。除非你知道它的具体类型,否则你不能恢复这个结构体,除非你有一个指向它的vtable的指针,否则你不能调用它的方法 - 除非你有权访问它的具体类型,否则你无法弄清楚。你可以序列化一个Vtable吗? – trentcl

+0

似乎是这样,但我希望有人会指出我失踪的东西。我有一个非惯用的解决方案,但增加了耦合到代码...所以我正在寻找更好的东西。 – Dash83

+3

你确定你想要多态而不仅仅是一个枚举吗?你需要你的代码来处理用户提供的类型吗? –

回答

6

它看起来像是陷入了我从C++转移到Rust时陷入的陷阱。尝试使用多态来建模一组固定类型的变体。 Rust的枚举(类似于Haskell的枚举,相当于Ada的变体记录类型)与其他语言中的经典枚举不同,因为枚举变体可以拥有自己的字段。

我建议你改变你的代码

#[derive(Debug, Serialize, Deserialize)] 
enum Contract { 
    Bar { data: Vec<Foo> }, 
    Baz { data: Vec<Foo>, tag: String }, 
} 

#[derive(Debug, Serialize, Deserialize)] 
struct Foo { 
    x: u32, 
    y: u32, 
} 

impl Contract { 
    fn do_something(&self) { 
     match *self { 
      Contract::Bar { ref data } => println!("I'm a Bar and this is my data {:?}", data), 
      Contract::Baz { ref data, ref tag } => { 
       println!("I'm Baz {} and this is my data {:?}", tag, data) 
      } 
     } 
    } 
} 
+0

使用结构Bar和Baz作为枚举的关联数据,但在这种设计中使用得非常多。谢谢! – Dash83

+0

如果存在具有类型参数特征的任意类型集合,那么该怎么办? – Shisoft

+0

@Shisoft不知道我明白。你为什么不开一个新的问题? –

相关问题