Наследование Serde's Serialize или Deserialize заставляет универсальный тип быть сериализуемым, хотя это не обязательно.

Мой тип A, который может содержать все, что реализует trait Trait, является сериализуемым, хотя тип, реализующий черту Trait, может не быть. В моем случае этого не может быть - это закрытый асимметричный ключ:

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

use serde::de::DeserializeOwned;
use serde::Serialize;

trait Trait {
    type SerialisableType: Clone + Serialize + DeserializeOwned;

    fn inner(&self) -> &Self::SerialisableType;
}

#[derive(Serialize, Deserialize)]
enum A<T: Trait> {
    Variant0(B<T>), // *** NOTE: Compiles if this is commented ***
    Variant1(T::SerialisableType),
}

#[derive(Serialize, Deserialize)]
struct B<T: Trait> {
    inner: T::SerialisableType,
}

// ==============================================

struct NonSerialisable {
    serialisable: Serialisable,
}

impl Trait for NonSerialisable {
    type SerialisableType = Serialisable;

    fn inner(&self) -> &Self::SerialisableType {
        &self.serialisable
    }
}

#[derive(Clone, Serialize, Deserialize)]
struct Serialisable(Vec<u8>);

#[derive(Serialize, Deserialize)]
enum E {
    Variant0(A<NonSerialisable>),
    Variant1(B<NonSerialisable>),
}

fn main() {}

детская площадка

Это ошибки с:

error[E0277]: the trait bound `NonSerialisable: serde::Serialize` is not satisfied
  --> src/main.rs:43:10
   |
43 | #[derive(Serialize, Deserialize)]
   |          ^^^^^^^^^ the trait `serde::Serialize` is not implemented for `NonSerialisable`
   |
   = note: required because of the requirements on the impl of `serde::Serialize` for `A<NonSerialisable>`
   = note: required by `serde::Serializer::serialize_newtype_variant`

error[E0277]: the trait bound `NonSerialisable: serde::Deserialize<'_>` is not satisfied
  --> src/main.rs:43:21
   |
43 | #[derive(Serialize, Deserialize)]
   |                     ^^^^^^^^^^^ the trait `serde::Deserialize<'_>` is not implemented for `NonSerialisable`
   |
   = note: required because of the requirements on the impl of `serde::Deserialize<'_>` for `A<NonSerialisable>`
   = note: required by `serde::de::VariantAccess::newtype_variant`

Если я закомментирую A::Variant0, как указано во встроенном комментарии в коде, он компилируется нормально. Это заставляет меня думать, что компилятор не может сделать вывод, что B<T> сериализуем, но тогда он действительно может сделать это, потому что он может понять, что E сериализуем, что потребует сериализации B.

В чем проблема?


person ustulation    schedule 26.04.2018    source источник


Ответы (1)


Во время раскрытия макроса компилятор еще не определил, на какой B делается ссылка внутри Variant0 или как этот B может использовать свои параметры типа. Таким образом, расширение макроса определяет границы признаков, которые будут работать в наиболее распространенных случаях того, чем может быть B, например, если бы B был Box или Vec. В этих случаях для сериализации B<T> потребуется T: Serialize, а для десериализации B<T> потребуется T: Deserialize<'de>.

Вы можете предоставить рукописные границы общего типа, чтобы заменить предполагаемые границы.

#[derive(Serialize, Deserialize)]
#[serde(bound = "")]
enum A<T: Trait> {
    Variant0(B<T>),
    Variant1(T::SerialisableType),
}
person dtolnay    schedule 26.04.2018
comment
это сработало - у меня уже было #[serde(bound(deserialize = ""))] уже в реальной реализации из-за предыдущих ошибок. Затем ящик с трейтом скомпилирован, и только тогда, когда я использую его в другом ящике, выдает ошибку. Выглядит довольно странно, поскольку я узнал, что изменять ящик только тогда, когда он позже используется другим. В любом случае я сделал bound = "" (как вы предложили) вместо того, чтобы просто десериализовать привязку, и теперь он работает. Спасибо ! - person ustulation; 26.04.2018