[英]Implementing a trait for multiple types at once
I have two structs and a trait:我有两个结构和一个特征:
struct A {
x: u32,
}
struct B {
x: u32,
}
trait T {
fn double(&self) -> u32;
}
I would like to implement T
for both structs using x
.我想使用
x
为两个结构实现T
。
Is there a way to write something like有没有办法写出类似的东西
impl T for A, B {
fn double(&self) -> u32 {
/* ... */
}
}
I would like to not use macros if possible.如果可能,我不想使用宏。
The only way to implement a trait once for many concrete types is to implement a trait for all types already implementing another trait.为许多具体类型实现一次 trait 的唯一方法是为所有已经实现另一个 trait 的类型实现一个 trait。
For example, you can implement a marker trait Xed
and then:例如,您可以实现一个标记特征
Xed
,然后:
impl<T> Double for T
where
T: Xed,
{
fn double(&self) {
/* ... */
}
}
However , Rust has principled generics.然而,Rust 有原则的泛型。 The only thing that you know about
T
in the previous implementation is that T
implements the Xed
trait
, and therefore the only associated types/functions you can use are those coming from Xed
.您在之前的实现中唯一了解
T
的是T
实现了Xed
trait
,因此您可以使用的唯一关联类型/函数是来自Xed
类型/函数。
A trait cannot expose a field/attribute, only associated types, constants and functions, so Xed
would need a getter for x
(which need not be called x
). trait 不能公开字段/属性,只能公开相关的类型、常量和函数,因此
Xed
需要x
的 getter(不需要称为x
)。
If you wish to rely on syntactic (and not semantic ) properties of the code, then use macros.如果您希望依赖代码的句法(而非语义)属性,请使用宏。
Creating a macro also solves your problem:创建宏也可以解决您的问题:
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() {}
Using the duplicate
attribute macro you can do the following:使用
duplicate
属性宏,您可以执行以下操作:
use duplicate::duplicate;
#[duplicate(name; [A]; [B])]
impl T for name {
fn double(&self) -> u32 {
self.x * 2
}
}
This will expand to two identical implementations for the two structs.这将扩展为两个结构的两个相同的实现。 I know you said you didn't want to use macros, but I interpret that as meaning you don't want to roll your own macro, so I think this is a good compromise.
我知道你说你不想使用宏,但我认为这意味着你不想推出自己的宏,所以我认为这是一个很好的妥协。
You could also use duplicate
to avoid repeating your struct definitions:您还可以使用
duplicate
来避免重复您的结构定义:
use duplicate::duplicate;
#[duplicate(name; [A]; [B])]
struct name {
x: u32,
}
Or go all-out if you for some reason need two identical structs with identical implements (at this point we should begin questioning why we need 2 structs at all :D):或者,如果您出于某种原因需要两个具有相同实现的相同结构(此时我们应该开始质疑为什么我们需要两个结构: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::*};
Since the internals of your structs are the same / share common components, you should extract them into a common struct and embed the common part back into the parent structs.由于结构的内部是相同的/共享公共组件,因此您应该将它们提取到公共结构中并将公共部分嵌入回父结构中。 The common struct would have the "complicated" implementation of the trait and then the parent struct's trait implementations would delegate to the common implementation:
公共结构将具有特征的“复杂”实现,然后父结构的特征实现将委托给公共实现:
trait T {
fn double(&self) -> u32;
}
struct A {
common: Common,
}
impl T for A {
fn double(&self) -> u32 {
self.common.double()
}
}
struct B {
common: Common,
}
impl T for B {
fn double(&self) -> u32 {
self.common.double()
}
}
struct Common {
x: u32,
}
impl T for Common {
fn double(&self) -> u32 {
self.x * 2
}
}
Any nicer code will require changes to the language.任何更好的代码都需要更改语言。 Two possible paths:
两种可能的路径:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.