2017-02-22 38 views
8

Próbuję zrobić serializację struktury, w której bajty zostaną ostatecznie wysłane w dół, zrekonstruowane i zostaną wywołane metody.W jaki sposób deserializować na cechę, a nie konkretnego typu?

stworzyłem cechę te kodowanym byłoby wdrożyć właściwe i używam serde i serde-cbor dla serializacji:

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

Kiedy próbuję zrekonstruować bajtów za pomocą cechę jako typ (biorąc pod uwagę, że nie wiem, który obiekt bazowy jest wysyłany), kompilator narzeka, że ​​cecha nie implementuje Sized cechę:

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` 

Myślę, że ma to sens, ponieważ kompilator nie wie, jak duża powinna być struktura i nie wie, jak ustawić bajty na nią. Jeśli zmienię linię gdzie deserializowania obiektu, aby określić rzeczywisty typ struct, to działa:

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

Czy istnieje lepszy wzór do osiągnięcia tego serializacji + polimorfizmu zachowanie?

+2

ja ... nie sądzę, że można to zrobić. Nie możesz odzyskać struktury, chyba że znasz jej konkretny typ i nie możesz wywoływać metod na niej, chyba że masz wskaźnik do jej tabeli vtable - czego nie możesz dowiedzieć się, chyba że masz dostęp do jej konkretnego typu. Czy można serializować vtable? – trentcl

+0

Wydaje się, że tak jest, ale miałem nadzieję, że ktoś wskaże coś, czego mi brakuje. Mam do tego rozwiązanie nie idiomatyczne, ale dodaję sprzężenie do kodu ... więc szukam czegoś lepszego. – Dash83

+3

Czy jesteś pewien, że chcesz polimorfizmu, a nie tylko wyliczenia? Czy potrzebujesz kodu do pracy z typami dostarczanymi przez użytkownika? –

Odpowiedz

6

Wygląda na to, że wpadłeś w tę samą pułapkę, w którą wpadłem, kiedy przeniosłem się z C++ do Rusta. Próba użycia polimorfizmu do modelowania stałego zestawu wariantów typu. Utwory Rusta (podobne do wyliczenia Haskella i odpowiadające wariantom rekordów Ada) różnią się od klasycznych wyrażeń w innych językach, ponieważ warianty enum mogą mieć własne pola.

Proponuję zmienić swój kod do

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

Użyto struktur Bar i Baz jako powiązanych danych dla wyliczenia, ale poszło prawie z tym projektem inaczej. Dzięki! – Dash83

+0

Co zrobić, jeśli istnieje arbitralny zestaw typów z cechy z parametrami typu? – Shisoft

+0

@Shisoft nie jestem pewien, czy rozumiem. Dlaczego nie otworzysz nowego pytania? –