一次实现多种类型的特征

jz8*_*z87 11 rust

我有两个结构和一个特征:

struct A {
    x: u32,
}

struct B {
    x: u32,
}

trait T {
    fn double(&self) -> u32;
}
Run Code Online (Sandbox Code Playgroud)

我想T为两个结构使用x.

有没有办法写出类似的东西

impl T for A, B {
    fn double(&self) -> u32 {
        /* ... */
    }
}
Run Code Online (Sandbox Code Playgroud)

我想尽可能不使用宏.

Mat*_* M. 13

对于许多具体类型实现特征一次的唯一方法是为已经实现另一特征的所有类型实现特征.

例如,您可以实现标记特征Xed,然后:

impl<T> Double for T
where
    T: Xed,
{
    fn double(&self) {
        /* ... */
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,Rust的原则是仿制药.您T在之前的实现中唯一知道的是T实现Xed trait,因此您可以使用的唯一关联类型/函数来自Xed.

特征不能公开字段/属性,只能显示关联的类型,常量和函数,因此Xed需要一个getter x(不需要调用x).

如果您希望依赖代码的语法(而非语义)属性,那么请使用宏.


She*_*ter 10

创建宏也可以解决您的问题:

struct A {
    x: u32,
}

struct B {
    x: u32,
}

trait T {
    fn double(&self) -> u32;
}

macro_rules! impl_T {
    (for $($t:ty),+) => {
        $(impl T for $t {
            fn double(&self) -> u32 {
                self.x * 2
            }
        })*
    }
}

impl_T!(for A, B);

fn main() {}
Run Code Online (Sandbox Code Playgroud)


Ema*_*oun 6

使用duplicate属性的宏可以做到以下几点:

use duplicate::duplicate;
#[duplicate(name; [A]; [B])]
impl T for name {
    fn double(&self) -> u32 {
        self.x * 2
    }
}
Run Code Online (Sandbox Code Playgroud)

这将扩展为两个结构的两个相同的实现。我知道你说你不想使用宏,但我认为这意味着你不想推出自己的宏,所以我认为这是一个很好的妥协。

您还可以使用duplicate来避免重复您的结构定义:

use duplicate::duplicate;
#[duplicate(name; [A]; [B])]
struct name {
    x: u32,
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您出于某种原因需要两个具有相同实现的相同结构(此时我们应该开始质疑为什么我们需要两个结构:D):

use duplicate::duplicate;
#[duplicate(
     mod_name struct_name; 
     [a]      [A]; 
     [b]      [B];
)]
mod mod_name {
    pub struct name {
        x: u32,
    }
    impl T for name {
        fn double(&self) -> u32 {
            self.x * 2
        }
    }
}
mod a;
mod b;
pub use self::{a::*, b::*};
Run Code Online (Sandbox Code Playgroud)