使用 Rust 空类型作为泛型绑定

Using Rust empty type as a generic bound

如何将 Rust 泛型类型约束为空类型?我需要创建一个具有可选值的类型,这样如果泛型类型是 (),它就不会使用任何内存。这是一个简单的示例 - Data 可以是 i32, ()(4 个字节),也可以是 i32, i32(8 个字节)。两种情况都有 add()。我收到此错误(这是有道理的,但不确定如何避免)。我需要处理所有有效的数字类型。

error[E0119]: conflicting implementations of trait `std::ops::Add` for type `Data<(), ()>`
...
note: upstream crates may add a new impl of trait `num_traits::Num` for type `()` in future versions
use num_traits::Num;

trait MyNumericType: Num {}
impl<T: Num> MyNumericType for T {}

struct Data<T1: MyNumericType, T2> {
    a: T1,
    b: T2,
}

impl<T: MyNumericType> Add for Data<T, ()> {
    type Output = Self;

    fn add(self, other: Self) -> Self {
        Self {
            a: self.a + other.a,
            b: (),
        }
    }
}

impl<T: MyNumericType> Add for Data<T, T> {
    type Output = Self;

    fn add(self, other: Self) -> Self {
        Self {
            a: self.a + other.a,
            b: self.b + other.b,
        }
    }
}


impl<T1: MyNumericType,T2> Data<T1, T2>  {
    fn new(a: T1, b: T2) -> Self {
        Self { a, b }
    }
}

fn main() {
    let r1 = Data::new(1, 2) + Data::new(3, 4);
    let r2 = Data::new(1, ()) + Data::new(2, ());
}

问题是您无法控制 () 类型,所以有人可以在您完全不知道并且没有恶意的情况下编写 impl 来破坏您的代码。 Rust 禁止这种远距离操作。

幸运的是,() 是一个非常简单的类型。所以我们可以自己做。

#[derive(Clone, Copy)]
struct MyUnit;

MyUnit() 基本相同,除了它在 你的 箱子里,而不是 Rust 的 stdlib 和其他人的箱子里。如果有人出现并为 MyUnit 写了一个 impl,那么他们一定已经将你的箱子作为依赖项,因此他们意识到了风险。然后用 Data<T, MyUnit> 而不是 Data<T, ()> 来写你的 impl。它仍然是 zero-sized 类型,因此受到与 ().

相同的所有优化。