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

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特性.尽管如此,我仍然处于 rust 病的学习阶段,如果可能的话,我想学习如何只用STD来做到这一点.

那么,让我们开始实现i8From<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);

显然,这是相同的代码,所以它不起作用.

目前,我发现的唯一简单的可能性就是创建一个新类型,就像编译器告诉我的那样.还有别的办法吗?

推荐答案

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

这将编译以下内容:

#[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);
}

Rust相关问答推荐

收集RangeInclusive T到Vec T<><>

我怎样才能从一个Rust 的日期中go 掉3年?

返回的future 不是`发送`

为什么实例方法可以像Rust中的静态方法一样被调用?

如何导入crate-type=[";cdylib;]库?

在使用AWS SDK for Rust时,如何使用硬编码访问密钥ID和密钥凭据?

完全匹配包含大小写的整数范围(&Q;)

写入引用会更新基础值,但引用会打印意外的值

为什么 `Deref` 没有在 `Cell` 上实现?

tokio::sync::broadcast::Receiver 不是克隆

如何正确使用git2::Remote::push?

返回迭代器考虑静态生命周期类型

Google chrome 和 Apple M1 中的计算着色器

返回优化后的标题:返回异步块的闭包的类型擦除

Rust并发读写引起的死锁问题

使用 serde_json 进一步处理字段

是否有适当的方法在参考 1D 中转换 2D 数组

提取 struct 生成宏中字段出现的索引

有没有办法在 Rust 中对 BigInt 进行正确的位移?

有没有比多个 push_str() 调用更好的方法将字符串链接在一起?