You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust中声明支持两种结构体类型参数的函数

Rust 中处理相似结构体共享逻辑的方案

你有两个仅差一个字段的结构体,需要提取依赖共享字段的重复逻辑,同时保留各自类型供其他函数使用,以下是几种Rust风格的实现方式:

方案一:定义共享 Trait(最推荐)

通过定义Trait抽象共享字段的访问方法,让两个结构体实现该Trait,就能用泛型函数复用逻辑:

pub struct EpochSigned {
    pub attr_a: u32,
    pub attr_b: u32,
    pub attr_c: u32
}

pub struct EpochUnsigned {
    pub attr_a: u32,
    pub attr_b: u32
}

// 定义共享Trait,暴露需要的字段访问方法
pub trait EpochCommon {
    fn attr_a(&self) -> u32;
    fn attr_b(&self) -> u32;
}

// 为两个结构体实现Trait
impl EpochCommon for EpochSigned {
    fn attr_a(&self) -> u32 {
        self.attr_a
    }
    fn attr_b(&self) -> u32 {
        self.attr_b
    }
}

impl EpochCommon for EpochUnsigned {
    fn attr_a(&self) -> u32 {
        self.attr_a
    }
    fn attr_b(&self) -> u32 {
        self.attr_b
    }
}

// 共享逻辑函数,接受任何实现了EpochCommon的类型
fn my_fn<T: EpochCommon, U: EpochCommon>(epoch1: &T, epoch2: &U) {
    // 直接使用共享字段的访问方法
    println!("epoch1 attr_a: {}, epoch2 attr_b: {}", epoch1.attr_a(), epoch2.attr_b());
    // 其他共享逻辑代码
}

// 使用示例
fn main() {
    let signed = EpochSigned { attr_a: 1, attr_b: 2, attr_c: 3 };
    let unsigned = EpochUnsigned { attr_a: 4, attr_b: 5 };
    
    my_fn(&signed, &unsigned);
    my_fn(&signed, &signed);
}

这种方式类型安全,编译时检查,后续新增相似结构体只需实现Trait即可复用逻辑。

方案二:提取共享字段到独立结构体(组合式设计)

把共享字段抽成单独的结构体,原结构体通过组合嵌入这个核心结构体,共享逻辑直接操作核心结构体:

// 提取共享字段为独立结构体
#[derive(Debug)]
pub struct EpochCore {
    pub attr_a: u32,
    pub attr_b: u32,
}

// 重构原结构体,嵌入核心字段
pub struct EpochSigned {
    pub core: EpochCore,
    pub attr_c: u32,
}

pub struct EpochUnsigned {
    pub core: EpochCore,
}

// 共享逻辑直接操作EpochCore
fn my_fn(epoch1: &EpochCore, epoch2: &EpochCore) {
    println!("epoch1 attr_a: {}, epoch2 attr_b: {}", epoch1.attr_a, epoch2.attr_b);
}

// 使用示例
fn main() {
    let signed = EpochSigned {
        core: EpochCore { attr_a: 1, attr_b: 2 },
        attr_c: 3,
    };
    let unsigned = EpochUnsigned {
        core: EpochCore { attr_a: 4, attr_b: 5 },
    };
    
    my_fn(&signed.core, &unsigned.core);
}

这种方式语义清晰,原结构体保留各自的独特字段,其他需要处理具体类型的函数可以直接操作外层结构体。

方案三:使用枚举(适合需偶尔区分类型的场景)

如果共享逻辑中需要偶尔处理两种类型的差异,可以用枚举包裹两个结构体,在函数内匹配提取共享字段:

pub struct EpochSigned {
    pub attr_a: u32,
    pub attr_b: u32,
    pub attr_c: u32
}

pub struct EpochUnsigned {
    pub attr_a: u32,
    pub attr_b: u32
}

// 定义枚举包裹两种类型
pub enum Epoch {
    Signed(EpochSigned),
    Unsigned(EpochUnsigned),
}

// 共享逻辑函数
fn my_fn(epoch1: &Epoch, epoch2: &Epoch) {
    // 辅助函数提取共享字段
    let extract_core = |epoch: &Epoch| -> (u32, u32) {
        match epoch {
            Epoch::Signed(s) => (s.attr_a, s.attr_b),
            Epoch::Unsigned(u) => (u.attr_a, u.attr_b),
        }
    };

    let (a1, b1) = extract_core(epoch1);
    let (a2, b2) = extract_core(epoch2);
    println!("a1: {}, b2: {}", a1, b2);
}

这种方式适合需要在共享逻辑中偶尔区分类型的场景,若只是单纯复用共享字段逻辑,前两种方案更简洁。

内容的提问来源于stack exchange,提问作者Milkncookiez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 11:35:53