【问题标题】:Implementing a trait for multiple types at once一次为多种类型实现一个特征
【发布时间】:2016-08-25 16:18:03
【问题描述】:

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

struct A {
    x: u32,
}

struct B {
    x: u32,
}

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

我想使用x 为这两个结构实现T

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

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

如果可能,我不想使用宏。

【问题讨论】:

    标签: rust


    【解决方案1】:

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

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

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

    然而,Rust 有原则性的泛型。在前面的实现中,您唯一了解的TT 实现了Xed trait,因此您可以使用的唯一关联类型/函数是来自Xed 的那些。

    特征不能公开字段/属性,只能公开关联的类型、常量和函数,因此Xed 需要一个用于x 的getter(不需要称为x)。

    如果您希望依赖代码的句法(而不是语义)属性,请使用宏。

    【讨论】:

    • 问题是,我想访问我的特征实现中的字段。因此出现了问题。
    • @jz87:如前所述,在 Xed 特征中创建一个 getter 或使用宏。不支持将特征中的“映射字段”到 Rust(可能永远不会,因为 getter 就足够了)。
    • 有没有办法让 getter 保持私有,而其他 trait 方法是公开的?
    • @eldruin: Trait 方法总是公开的,但 trait 本身可以是私有的。要保持 getter 私有,您可以直接在类型(固有方法)或私有 trait 上实现。
    【解决方案2】:

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

    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() {}
    

    【讨论】:

      【解决方案3】:

      使用the duplicate_item attribute macro,您可以执行以下操作:

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

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

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

      use duplicate::duplicate_item;
      #[duplicate_item(name; [A]; [B])]
      struct name {
          x: u32,
      }
      

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

      use duplicate::duplicate;
      duplicate!{
          [ name; [A]; [B] ]
          pub struct name {
              x: u32,
          }
          impl T for name {
              fn double(&self) -> u32 {
                  self.x * 2
              }
          }
      }
      

      注意这次使用duplicate类函数宏来同时复制结构和实现。

      【讨论】:

      • 您回答的第一个代码块对我不起作用。基于 crate 文档 (docs.rs/duplicate/0.2.2/duplicate) 的小调整:A、B 应分别包含在自己的 [] 方括号中。使用 duplicate::duplicate #[duplicate(name; [A]; [B])] impl T for name {...
      • 这太棒了!正是我正在做的事情所需要的。 :)
      【解决方案4】:

      由于您的结构的内部结构是相同的/共享公共组件,您应该将它们提取到一个公共结构中并将公共部分嵌入回父结构中。公共结构将具有特征的“复杂”实现,然后父结构的特征实现将委托给公共实现:

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

      任何更好的代码都需要更改语言。两种可能的路径:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-08-15
        • 1970-01-01
        • 2019-12-08
        • 1970-01-01
        • 2019-12-08
        • 2015-04-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多