展平非此即彼的结构到另一个生 rust 的结构中

oogrdqng  于 2023-11-19  发布在  其他
关注(0)|答案(2)|浏览(112)

我试图在rust中创建一个灵活但特定类型的结构体。让我们将结构体命名为Analysis。所有Analysis结构体必须具有字段nameidcreatedmodified。但有3种不同的分析:

// 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>,
}


我的目标是创建一个结构体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,
}


serde(flatten)almost 得到了我想要的。当我在OpenAPI文档中检查这个时,分析结构体将始终具有“common”字段,并且需要一个名称为Chemical,Physical或Biological的条目,每个条目都有各自的字段。


的数据
我想对这些属性进行“去 shell 化”,让它们直接扁平化到父结构体中,而不是要求它们在一个命名的属性下。
另外,我如何在父Analysis结构analysis_type中要求一个属性,即AnalysisEnum类型,专门对应于每个AnalysisEnum?例如:

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)

k7fdbhmy

k7fdbhmy1#

您要查找的内容名为#[serde(tag = "analysis_type")](您可以将`“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,
}

字符串
Playground ]
有关如何在Serde中表示枚举的完整参考,请参见https://serde.rs/enum-representations.html

rt4zxlrg

rt4zxlrg2#

既然可以创建一个枚举,为什么还要创建五个不同的类型(AnalysisEnumAnalysisTypeChemicalAnalysisPhysicalAnalysisBiologicalAnalysis)呢?

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,
}

字符串
我想对这些属性进行“去壳”,并将它们直接展平到父结构中,而不是要求它们位于命名属性之下。我该如何做到这一点?
没有。大小类型就是大小类型,它不能根据运行时的值而改变。你必须把事情弄得很清楚。不过我可能对你真正想要的是错的。
serde
也许你只想要tag = "type"
我想要的设计图案...
感觉是这样。

相关问题