提问人:Seth Lutske 提问时间:11/9/2023 更新时间:11/9/2023 访问量:47
在 rust 中将非此即彼结构扁平化为另一个结构
Flattening either-or structs into another struct in rust
问:
我正在尝试在 rust 中创建一个灵活但特定类型的结构。我们称之为 struct 。所有结构都必须具有字段 、 、 、 。但有 3 种不同类型的分析:Analysis
Analysis
name
id
created
modified
// all enums and struct use the #[derive(Serialize, Deserialize, ToSchema)] macro
pub enum AnalysisTypes {
Chemical,
Physical,
Biological,
}
每种特定的分析类型都有其自己的特定字段:
pub struct ChemicalAnalysis {
statistics: Vec<Statistic>, // doesn't matter what this is exactly
method_parameters: MethodParameters,
}
pub struct PhysicalAnalysis {
statistics: Vec<Statistic>,
}
pub struct BiologicalAnalysis {
sampling_information: Vec<SampleInformation>,
}
我的目标是创建一个 struct ,它具有上述所有常见属性,以及来自上述分析结构之一的所有属性。因此,我创建了一个枚举,它可以是其中任何一个,然后将其包含在我的结构中:Analysis
pub enum AnalysisEnum {
Chemical(ChemicalAnalysis),
Physical(PhysicalAnalysis),
Biological(BiologicalAnalysis),
}
pub struct Analysis {
name: String,
id: Uuid,
created: DateTime<Utc>,
modified: DateTime<Utc>,
#[serde(flatten)] // <------------ flatten values into struct here
more_fields: AnalysisEnum,
}
这几乎得到了我想要的东西。当我在 OpenAPI 文档中检查这一点时,分析结构将始终具有“通用”字段,并且需要一个名称为“化学”、“物理”或“生物”的条目,每个条目都有各自的字段。serde(flatten)
我想“de-shell”这些属性,并将它们直接展平到父结构中,而不是要求它们位于命名属性下。我该怎么做?
此外,我如何要求父结构中的属性,该属性的类型为 AnalysisEnum,专门对应于每个 AnalysisEnum?例如:Analysis
analysis_type
pub enum AnalysisTypes {
Chemical,
Physical,
Biological,
}
pub struct ChemicalAnalysis {
analysis_type: AnalysisTypes::Chemical, // this is not correct syntax, errors
statistics: Vec<Statistic>,
method_parameters: MethodParameters,
}
pub struct PhysicalAnalysis {
analysis_type: AnalysisTypes::Physical, // this is not correct syntax, errors
statistics: Vec<Statistic>,
}
...
如果这是一个简单的问题,或者我想要的设计模式不符合语言的精神,请原谅我。我来自打字稿背景,可以像这样轻松完成:
enum AnalysisTypes {
Chemical = "Chemical",
Physical = "Physical",
Biological = "Biological",
}
interface ChemicalAnalysis {
analysis_type: AnalysisTypes.Chemical,
statistics: Statistic[],
method_parameters: MethodParameters,
}
interface PhysicalAnalysis {
analysis_type: AnalysisTypes.Physical,
statistics:Statistic[],
}
interface BiologicalAnalysis {
analysis_type: AnalysisTypes.Biological,
sampling_information:SampleInformation[],
}
type Analysis = {
name: String;
id: Uuid;
created: DateTime<Utc>;
modified: DateTime<Utc>;
} & (ChemicalAnalysis | PhysicalAnalysis | BiologicalAnalysis)
答:
当可以制作一个枚举时,为什么要制作五种不同的类型(、、、、)、?AnalysisEnum
AnalysisType
ChemicalAnalysis
PhysicalAnalysis
BiologicalAnalysis
pub enum AnalysisType {
Chemical {
statistics: Vec<Statistic>,
method_parameters: MethodParameters,
},
Physical {
statistics: Vec<Statistic>,
},
Biological {
sampling_information: Vec<SampleInformation>,
},
}
pub struct Analysis {
name: String,
id: Uuid,
created: DateTime<Utc>,
modified: DateTime<Utc>,
spec: AnalysisType,
}
我想“de-shell”这些属性,并将它们直接展平到父结构中,而不是要求它们位于命名属性下。我该怎么做?
不。大小类型是大小类型,它不能根据运行时值进行更改。你必须把事情说得很清楚。不过,我可能错了你真正想要的。
塞尔德
也许你只是想要?tag = "type"
我想要的设计模式...
感觉是这样。
您要查找的内容称为(您可以将“analysis_type”)]“替换为要用于存储标记的字段的名称)。#[serde(tag = "analysis_type")]
#[derive(Serialize, Deserialize)]
#[serde(tag = "analysis_type")]
pub enum AnalysisEnum {
Chemical(ChemicalAnalysis),
Physical(PhysicalAnalysis),
Biological(BiologicalAnalysis),
}
#[derive(Serialize, Deserialize)]
pub struct Analysis {
name: String,
id: Uuid,
created: DateTime<Utc>,
modified: DateTime<Utc>,
#[serde(flatten)]
more_fields: AnalysisEnum,
}
(操场]
有关如何在 Serde 中表示枚举的完整参考,请参阅 https://serde.rs/enum-representations.html 。
评论
AnalysisTypes