rust 属性界限i8:来自< u8>不满意

cetgtptt  于 11个月前  发布在  其他
关注(0)|答案(2)|浏览(104)

为了论证的目的,假设我想学习如何构建一个表示2D向量的简单通用结构。

pub struct Vector<T> {
  x: T,
  y: T,
}

字符串
现在,很明显,我想构造新的向量:,一个给定坐标的向量,零向量,甚至一个单位向量。

impl<T: Default + From<u8>> Vector<T> {
  pub fn new(x: T, y: T) -> Self {
    Self { x, y }
  }

  pub fn zero() -> Self {
    Self { x: T::default(), y: T::default() }
  }

  pub fn unit() -> Self {
    Self { x: T::from(1), y: T::from(1) }
  }
}


我们试试这个

fn main() {
  let v1 = Vector<u8>::new(1, 2);
  let v2 = Vector<u8>::unit();
}


这就像一个魔咒。然而,让我们从u8i8

fn main() {
    let v1 = Vector::<i8>::new(1, 2);
    let v2 = Vector::<i8>::unit();
}


然后我们得到以下编译错误
特征界限i8: From<u8>未满足
从这里我可以做什么才能使用任何数字类型?
我知道可以使用num crate中的FromPrimitive trait,但我仍处于rust的学习阶段,我想学习如何在可能的情况下只使用std。
那么,让我们开始为i8实现From<u8>

impl From<u8> for i8 {
    fn from(value: u8) -> Self {
        value as Self
    }
}


嗯,它不转好:

error[E0117]: only traits defined in the current crate can be implemented for primitive types
  --> main.rs:17:1
   |
1  | impl From<u8> for i8 {
   | ^^^^^--------^^^^^--
   | |    |            |
   | |    |            `i8` is not defined in the current crate
   | |    `u8` is not defined in the current crate
   | impl doesn't use only types from inside the current crate
   |
   = note: define and implement a trait or new type instead


所以,让我们使用宏?

macro_rules! impl_fromu8 {
    ($($t:ty)*) => {
        $(
            impl From<u8> for $t {
                fn from(value: u8) -> Self {
                    value as Self
                }
            }
        )*
    };
}

impl_fromu8!(i8);


显然,这是相同的代码,所以它不工作。
现在我发现的唯一简单的方法就是按照编译器告诉我的那样创建一个新的类型,还有别的方法吗?

92dk7w1h

92dk7w1h1#

虽然From<u8>没有为i8实现,但TryInto<u8>是。这可能是因为转换可能会失败。然而,在这种情况下,我们知道它不能,所以我们可以使用unwrap。
这编译:

#[allow(dead_code)]
#[derive(Debug)]
pub struct Vector<T> {
  x: T,
  y: T,
}

impl<T: Default + TryFrom<u8>> Vector<T> {
  pub fn new(x: T, y: T) -> Self {
    Self { x, y }
  }

  pub fn zero() -> Self {
    Self { x: T::default(), y: T::default() }
  }

  pub fn unit() -> Self where <T as TryFrom<u8>>::Error: core::fmt::Debug {
    Self { x: T::try_from(1).unwrap(), y: T::try_from(1).unwrap() }
  }
}

fn main() {
    let v1 = Vector::<i8>::new(1, 2);
    let v2 = Vector::<i8>::unit();
    
    println!("v1 = {:?}, v2 = {:?}", v1, v2);
}

字符串

ego6inou

ego6inou2#

另一种选择是使用num-traits,它为这种情况定义了ZeroOne特征。

相关问题