如何对接受具有共同属性的不同结构的 Rust 函数进行重复数据删除?

Posted

技术标签:

【中文标题】如何对接受具有共同属性的不同结构的 Rust 函数进行重复数据删除?【英文标题】:How to deduplicate Rust functions accepting different structs with common properties? 【发布时间】:2022-01-15 11:55:39 【问题描述】:

我有几个结构体(StructXStructY),还有一个结构体具有之前结构体的所有公共引用属性(StructCommon)。

我还为StructXStructY 提供了一个返回StructCommon 的函数,但我的问题是我必须为它编写两个函数。

pub struct StructX<'a> 
    a: &'a str,
    b: &'a str,
    x: &'a str,


pub struct StructY<'a> 
    a: &'a str,
    b: &'a str,
    y: &'a str,


pub struct StructCommon<'a> 
    a: &'a str,
    b: &'a str,


impl<'a> StructCommon<'a> 
    pub fn from_x<T>(serialized: &StructX) -> StructCommon<'a>
    
        StructCommon 
            a: serialized.a,
            b: serialized.b,
        
    

    pub fn from_y<T>(serialized: &StructY) -> StructCommon<'a>
    
        StructCommon 
            a: serialized.a,
            b: serialized.b,
        
    

    // Pseudo-Rust proposed solution example:
    // pub fn from_either<T>(serialized: &StructX | &StructY) -> StructCommon<'a>
    // 
    //     StructCommon 
    //         a: serialized.a,
    //         b: serialized.b,
    //     
    // 

我该如何 - 如果可能 - 删除 from_x()from_y() 方法的重复项,这样我只需编写一次提取公共属性的逻辑**?**

我写了一个假想的伪代码解决方案示例方法被注释掉了,叫做from_either()

【问题讨论】:

您需要使用至少一个代表具有特定属性的特征,也就是说,如果没有真实的用例,很难建议该怎么做,我的简单建议是保持简单,顺其自然那样。 【参考方案1】:

我不认为你可以在 Rust 中使用泛型直接表达你想要的东西,除非你使用像 get_a()get_b() 这样的方法编写一个 trait 并将它用于你的 from_either() 的泛型实现。不过,这确实不会减少您的样板文件。

但是,procedural macros 看起来很适合您正在尝试做的事情。例如,您可以为StructXStructY 创建一个实现Into&lt;StructCommon&gt; 的派生宏,该宏可以为您编写样板代码。

【讨论】:

编写程序宏并非易事,可能不值得。但这是“一般”表达StructX.a 映射到StructCommon.a 的概念的唯一方法,因为这两个字段具有相同的名称。具有相同名称的字段在语言级别上没有任何意义。【参考方案2】:

还有另一个针对您的具体问题的答案,但我提出了一个替代解决方案,即让StructXStructY 包含StructCommon,而不是让字段恰好与@ 中的字段具有相同的名称和类型987654325@。这通过仅返回内部结构来减少转换的样板:

pub struct StructX<'a> 
    common: StructCommon<'a>,
    x: &'a str,


pub struct StructCommon<'a> 
    a: &'a str,
    b: &'a str,


impl<'a> Into<StructCommon<'a>> for StructX<'a> 
    fn into(self) -> StructCommon<'a> 
        self.common
    

这仍然是一些样板,但要少得多,并且在更改公共字段时不需要更改。

【讨论】:

这是一个很酷的主意。虽然在我(或者更确切地说是开源项目)的真实代码中,StructX 和 StructY 不改变非常重要,因为它们在其他代码部分中按原样序列化,并且由于向后兼容性,序列化格式不能改变。跨度> @AttilaSzeremi 如果使用serde,可以使用#[serde(flatten)]

以上是关于如何对接受具有共同属性的不同结构的 Rust 函数进行重复数据删除?的主要内容,如果未能解决你的问题,请参考以下文章

具有共同属性但值不同的派生类的正确设计设置

如何创建具有计时时区的通用 Rust 结构?

Rust:从(仅)<T> 不同的函数返回通用结构

实体具有某些共同属性时的模型结构

使构造函数仅接受 C# 中具有 [Serializable] 属性的对象

第四章 类与对象