如何创建一个可以用 Serde 序列化并保留类型信息的通用结构?
How do I create a generic struct that can be serialized with Serde and retain type information?
我想使用 Serde 序列化一个通用的数据结构。
我的库的用户应该能够提供他们自己的实现 Serialize
和 Deserialize
的结构。我应该能够取回他们用于序列化数据的值的原始类型信息。
我该怎么做?
我试过这样的事情:
#[derive(Serialize, Deserialize)]
struct Message<V> {
key: Key,
value: V,
}
我想在反序列化数据后取回 V
的类型。
这是这样做的方法还是我偏离了轨道?
我希望用户能够扩展可能的 values/types。我想要枚举的行为,但用户可以灵活地添加自己的结构作为可能的候选者。类似于 this code 但它们都需要唯一的 ids.
我敢肯定,这在一般意义上是完全不可能的。
每种类型都可以控制自己的序列化。这意味着多种类型最终可能会序列化为 相同的值 :
#[derive(Debug, Deserialize, Serialize)]
struct Age(i32);
#[derive(Debug, Deserialize, Serialize)]
struct Weight(i32);
fn main() {
let a = Age(42);
let a_str = serde_json::to_string(&a).unwrap();
println!("{}", a_str); // 42
let b: Weight = serde_json::from_str(&a_str).unwrap();
println!("{:?}", b);
}
您可以尝试在序列化数据中建立标识类型的标记,但最终会出现同样的问题:总是存在冲突的可能性。
更根本的是,这样的概念在 Rust 中是无效的,因为 Rust 中每种类型都必须在编译时具有已知大小。无法反序列化为 未知大小 .
的变量
同样重要的是,您会为泛型 V
提供什么类型?编译代码时不能"forget"指定所有泛型类型。
正因为如此,平时这种事情根本就不会出现。如果用户使用具体类型调用您的序列化代码,他们可以使用相同的具体类型调用您的反序列化代码。
I want the behavior of enums, but flexibility for the user to add their own structs.
这听起来像 特质对象。
另请参阅:
实现这种想法的最佳方式是限制 V 的类型,然后使用结构名称作为识别模块类型+字符串的手段。
示例
pub struct Message<V: Serialize + Deserialize> {
key: keytype,
value: V,
crate_path: String
}
然后使用类似 sha 的东西为结构名称生成哈希,反序列化以检查结构名称。
我想使用 Serde 序列化一个通用的数据结构。
我的库的用户应该能够提供他们自己的实现 Serialize
和 Deserialize
的结构。我应该能够取回他们用于序列化数据的值的原始类型信息。
我该怎么做?
我试过这样的事情:
#[derive(Serialize, Deserialize)]
struct Message<V> {
key: Key,
value: V,
}
我想在反序列化数据后取回 V
的类型。
这是这样做的方法还是我偏离了轨道?
我希望用户能够扩展可能的 values/types。我想要枚举的行为,但用户可以灵活地添加自己的结构作为可能的候选者。类似于 this code 但它们都需要唯一的 ids.
我敢肯定,这在一般意义上是完全不可能的。
每种类型都可以控制自己的序列化。这意味着多种类型最终可能会序列化为 相同的值 :
#[derive(Debug, Deserialize, Serialize)]
struct Age(i32);
#[derive(Debug, Deserialize, Serialize)]
struct Weight(i32);
fn main() {
let a = Age(42);
let a_str = serde_json::to_string(&a).unwrap();
println!("{}", a_str); // 42
let b: Weight = serde_json::from_str(&a_str).unwrap();
println!("{:?}", b);
}
您可以尝试在序列化数据中建立标识类型的标记,但最终会出现同样的问题:总是存在冲突的可能性。
更根本的是,这样的概念在 Rust 中是无效的,因为 Rust 中每种类型都必须在编译时具有已知大小。无法反序列化为 未知大小 .
的变量同样重要的是,您会为泛型 V
提供什么类型?编译代码时不能"forget"指定所有泛型类型。
正因为如此,平时这种事情根本就不会出现。如果用户使用具体类型调用您的序列化代码,他们可以使用相同的具体类型调用您的反序列化代码。
I want the behavior of enums, but flexibility for the user to add their own structs.
这听起来像 特质对象。
另请参阅:
实现这种想法的最佳方式是限制 V 的类型,然后使用结构名称作为识别模块类型+字符串的手段。
示例
pub struct Message<V: Serialize + Deserialize> {
key: keytype,
value: V,
crate_path: String
}
然后使用类似 sha 的东西为结构名称生成哈希,反序列化以检查结构名称。