我可以相信两个相同结构的序列化是相同的吗?

Mat*_*nti 3 rust serde

考虑以下代码:

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct MyStruct {
   a: u32,
   b: u32
}

#[derive(Serialize, Deserialize)]
#[serde(rename = "MyStruct")]
struct AlsoMyStruct {
   a: u32,
   b: u32
}
Run Code Online (Sandbox Code Playgroud)

我想知道我是否可以安全地做类似的事情:

let ser = any_encoding::serialize(&MyStruct{a: 33, b: 44}).unwrap();
let deser: AlsoMyStruct = any_encoding::deserialize(&ser).unwrap();
Run Code Online (Sandbox Code Playgroud)

其中any_encoding是,例如bincodejson或任何其他 Serde 支持的编码。在我看来,这应该很好地工作:两个结构具有相同的名称(我明确重命名AlsoMyStruct"MyStruct")和完全相同的字段:相同的字段名称、相同的字段类型、相同的字段顺序。

但是,我想知道:这真的能保证有效吗?MyStruct或者 Serde 序列化器/反序列化器是否可能在/的表示中包含一些其他的、极端情况的、可能与平台相关的、不可预见的信息,AlsoMyStruct这些信息可能会导致两种表示不兼容?

jon*_*sbb 5

一般来说,不,你不能指望这能起作用。原因是 Serde 和任何反序列化器都不能保证您可以往返数据()。这意味着如果您在两个地方使用相同的结构,您甚至不能期望它在所有情况下都有效。

例如,JSON 无法往返Option<()>,并且非自描述格式(如 bincode)不支持未标记的枚举。类型签名中没有任何内容强制往返。
以下是反序列化可能失败的一些原因:

  • 使用skip_serializing_none非自描述格式(serde #1732)。
  • 任何调用 的东西deserialize_any,例如未标记的、相邻标记的或内部标记的枚举(serde #1762)。
  • 反序列化期间借用,例如 for&'de str&'de [u8]serde_json&'de str在没有转义序列的情况下支持,并且从不支持&'de [u8].
  • 某些格式无法序列化某些类型,例如,JSON 不支持结构体作为映射键,而 bincode 仅支持已知长度的序列(bincode #167)。
  • 类型仅实现其中一个特征 ( Serializer/ Deserializer) 或实现不匹配,例如序列化为数字但反序列化为字符串。

话虽这么说,这在某些情况下是可行的。结构体应具有相同的名称和相同顺序的字段。类型或者更确切地说Serialize/Deserialize实现也需要支持往返。从Option<()>上面来看,它还取决于Serializer/Deserializer实现是否可以往返它们,即使Serialize/Deserialize实现确实支持它。

许多类型确实尝试支持往返,因为这是最常见的期望。

  • OP 问“这实际上保证有效吗”,答案显然是否定的。通常它在实践中会起作用,但您也可以故意破坏它或遇到未标记枚举、结构扁平化或使用“skip_serializing_if”(破坏往返二进制代码)的边缘情况。 (4认同)
  • @Stargateur 我添加了一些为什么往返可能不起作用的例子。这不仅仅影响边缘情况或相等检查。 (3认同)