2017-02-22 35 views
8

Tôi đang cố gắng thực hiện tuần tự hóa cấu trúc, trong đó các byte cuối cùng sẽ được gửi xuống một đường ống, được xây dựng lại và các phương thức được gọi trên chúng.Làm thế nào để tôi deserialize vào đặc điểm, không phải là một loại cụ thể?

Tôi tạo ra một đặc điểm các cấu trúc sẽ thực hiện cho phù hợp và tôi đang sử dụng serde và serde-cbor cho serialization:

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(); 
} 

Khi tôi cố gắng để tái tạo lại các byte bằng cách sử dụng đặc điểm như các loại (cho rằng tôi sẽ không biết được tiềm ẩn đối tượng đang được gửi), trình biên dịch phàn nàn rằng đặc tính không thực hiện Sized đặc điểm:

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` 

Tôi đoán nó có ý nghĩa vì trình biên dịch không biết cấu trúc được cho là lớn đến mức nào và không biết cách xếp hàng các byte cho nó. Nếu tôi thay đổi dòng mà tôi deserialize đối tượng để xác định cấu trúc kiểu thực tế, nó hoạt động:

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

Có một mô hình tốt hơn để đạt được serialization + đa hình hành vi này?

+2

Tôi ... không nghĩ rằng bạn có thể làm điều đó. Bạn không thể phục hồi cấu trúc trừ khi bạn biết loại bê tông của nó, và bạn không thể gọi các phương thức trên nó trừ khi bạn có con trỏ đến vtable của nó - bạn không thể tìm ra trừ khi bạn có quyền truy cập vào loại cụ thể của nó. Bạn có thể serialize một vtable? – trentcl

+0

Có vẻ như vậy, nhưng tôi đã hy vọng một người nào đó sẽ chỉ ra một cái gì đó tôi đang mất tích. Tôi có một giải pháp không thành ngữ cho việc này nhưng thêm sự liên kết vào mã ... vì vậy tôi đang tìm kiếm một cái gì đó tốt hơn. – Dash83

+3

Bạn có chắc bạn muốn đa hình và không đơn giản là một enum? Bạn có cần mã của bạn để làm việc với các loại do người dùng cung cấp không? –

Trả lời

6

Có vẻ như bạn rơi vào cùng một cái bẫy mà tôi đã rơi vào khi tôi chuyển từ C++ sang Rust. Đang cố gắng sử dụng đa hình để mô hình hóa một tập hợp biến thể cố định của một loại. Enums của Rust (tương tự như enums của Haskell, và tương đương với các loại bản ghi biến thể của Ada) khác với enums cổ điển trong các ngôn ngữ khác, bởi vì các biến thể enum có thể có các lĩnh vực của riêng mình.

Tôi đề nghị bạn thay đổi mã của bạn để

#[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

Sử dụng cấu trúc Bar và Baz làm dữ liệu liên quan cho enum, nhưng đã đi khá nhiều với thiết kế này nếu không. Cảm ơn! – Dash83

+0

Điều gì sẽ xảy ra nếu có tập hợp tùy ý loại từ đặc điểm với thông số loại? – Shisoft

+0

@Shisoft không chắc tôi hiểu. Tại sao bạn không mở một câu hỏi mới? –

Các vấn đề liên quan