我知道有一个类似的问题here,但我还不能使它适合我的用例。
我有一个嵌套在其他结构体中的Model结构体。模型可以有两种不同类型的Config对象,ModelConfig或SeedConfig。除了几个字段之外,它们几乎是相同的。目前,我需要Model的两个具体实现(SeedModel和ModelModel)来更改config字段,这导致了所有方法和trait实现的重复。
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct MetaModel {
pub model: Model
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct Model {
pub name: String,
pub config: Option<ModelConfig>
}
我尝试过的:
- 使用泛型:这将泛型类型推到链的上方,并导致非常复杂的定义和区域,在这些区域中我没有上下文来创建父结构(即,MetaModel定义在创建时无法访问Model定义)。
这最终会导致the type parameter
C is not constrained by the impl trait, self type, or predicates unconstrained type parameter
错误
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct MetaModel<C> {
pub model: Model<C>
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct Model<C> {
pub name: String,
pub config: Option<C>
}
- 特征对象:这不起作用,因为serde不能序列化trait对象
pub trait Config {}
pub struct ModelConfig;
impl Config for ModelConfig {}
pub struct SeedConfig;
impl Config for SeedConfig {}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct Model {
pub name: String,
pub config: Option<Box<dyn Config>
}
我想做的是:
impl OtherTrait for Model {
type Value = Model;
fn build_model(&self, m: DerivedMeta) -> Result<Self::Value, &'static str> {
Ok(Model {
// Either a SeedConfig or a ModelConfig
})
}
}
1条答案
按热度按时间lsmepo6l1#
我将使用
#[serde(flatten)]
和#[serde(untagged)]
的组合:flatten
的序列解释:将此字段的内容平铺到定义它的容器中。
这将删除序列化表示和Rust数据结构表示之间的一个结构级别。
关于
untagged
的解释:没有明确的标记来标识数据包含的变量,Serde将尝试按顺序将数据与每个变量进行匹配,第一个反序列化成功的变量将被返回。
通过将这两种行为结合起来,我们可以得到以下行为:
flatten
允许所有共享字段和特定字段在配置中处于同一级别untagged
允许我们避免在配置中添加显式标记specific
枚举