【问题标题】:rust implement trait for multiple typesrust 实现多种类型的特征
【发布时间】:2022-08-15 04:55:48
【问题描述】:

我试图一次为多种类型实现一个特征,我发现避免代码重复的唯一方法是将所有类型转换为一个通用结构并为该结构实现特征,如下所示。

trait Increment {
    fn increment(&self) -> Option<String>;
}

struct NumberWrapper {
    number: String,
}

impl Increment for NumberWrapper {
    fn increment(&self) -> Option<String> {
        let num: Result<u64, _> = self.number.parse();
        match num {
            Err(_) => None,
            Ok(x) => Some((x + 1).to_string())
        }
    }
}

impl<T> From<T> for NumberWrapper where T: ToString {
    fn from(input: T) -> NumberWrapper {
        NumberWrapper { number: input.to_string() }
    }
}

fn main() {
    let number_u8: u8 = 10;
    println!("number_u8 is: {}", NumberWrapper::from(number_u8).increment().unwrap());
    let number_u32: u16 = 10;
    println!("number_u16 is: {}", NumberWrapper::from(number_u32).increment().unwrap());
    let number_u32: u32 = 10;
    println!("number_u32 is: {}", NumberWrapper::from(number_u32).increment().unwrap());
    let number_u64: u64 = 10;
    println!("number_u64 is: {}", NumberWrapper::from(number_u64).increment().unwrap());
}

有没有其他方法可以做到这一点?

【问题讨论】:

    标签: rust struct traits rust-cargo


    【解决方案1】:

    一揽子实施可用于为满足某些其他特征的所有类型实现特征。我不确定您的示例中的特征到底是什么意思,但我希望下面的示例说明了这个想法。

    use std::ops::Add;
    use num::traits::One;
    
    trait Increment {
        fn increment(&self) -> Option<String>;
    }
    
    impl<T> Increment for T
        where T: Add + Copy + One,
              <T as Add>::Output: ToString,
    {
        fn increment(&self) -> Option<String> {
            Some((*self + One::one()).to_string())
        }
    }
    
    fn main() {
        let number_u8: u8 = 10;
        println!("number_u8 is: {}", number_u8.increment().unwrap());
        let number_u32: u16 = 10;
        println!("number_u16 is: {}", number_u32.increment().unwrap());
        let number_u32: u32 = 10;
        println!("number_u32 is: {}", number_u32.increment().unwrap());
        let number_u64: u64 = 10;
        println!("number_u64 is: {}", number_u64.increment().unwrap());
    }
    

    【讨论】:

      【解决方案2】:

      我想到了两种更优雅地做到这一点的方法。首先,我猜你宁愿让你的特质看起来像这样:

      trait Increment {
          // It would probably be better to take `self` by value if you
          // just want this for numeric types which are cheaply copied,
          // but I'll leave it for generality.
          fn increment(&self) -> Option<Self> where Self: Sized;
      }
      

      我会假设这会向前发展(但请纠正我)。

      第一种方法使用一个非常简单的macro

      macro_rules! impl_increment {
          ($($t:ty),*) => {
              $(
                  impl Increment for $t {
                      fn increment(&self) -> Option<Self> {
                          self.checked_add(1)
                      }
                  }
              )*
          }
      }
      

      它只匹配一个规则,该规则读取用逗号分隔的任意数量的类型,并基于 Rust 中数字原语的 checked_add 方法为该类型实现 increment 方法。你可以这样称呼它:

      // This will create an impl block for each of these types:
      impl_increment!{u8, u16, u32, u64, i8, i16, i32, i64}
      
      fn main() {
          let x = 41u32;
          assert_eq!(x.increment(), Some(42));
          let y = -60_000i64;
          assert_eq!(y.increment(), Some(-59_999));
          let z = 255u8;
          assert_eq!(z.increment(), None);
      }
      

      或者,您可以通过转换为通用类型和从通用类型转换来类似于您已经在做的事情。在这种情况下,使用Into&lt;u64&gt;TryFrom&lt;u64&gt; 特征,所有小于u64 的无符号整数类型都实现:

      use std::convert::TryFrom;
      
      impl<T> Increment for T
      where T: Copy + Into<u64> + TryFrom<u64>
      {
          fn increment(&self) -> Option<Self> {
              let padded: u64 = (*self).into();
              TryFrom::try_from(padded + 1).ok()
          }
      }
      
      fn main() {
          let x = 41u32;
          assert_eq!(x.increment(), Some(42));
          let y = 60_000u64;
          assert_eq!(y.increment(), Some(60_001));
          let z = 255u8;
          assert_eq!(z.increment(), None);
      }
      

      这有更多的运行时开销,并且不能很好地概括(例如,不适用于有符号整数类型)。所以我会选择宏观路线。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-12-24
        • 2020-05-05
        • 2020-03-31
        • 1970-01-01
        • 1970-01-01
        • 2021-06-07
        • 2019-12-08
        相关资源
        最近更新 更多