为自定义特征提供一揽子特征实现 [英] Providing Blanket Trait Implementations for a Custom Trait

查看:35
本文介绍了为自定义特征提供一揽子特征实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在实现一个用于练习的快速几何板条箱,我想实现两个结构,VectorNormal(这是因为标准向量和法线向量映射通过某些变换方式不同).我已经实现了以下特征:

I am implementing a quick geometry crate for practice, and I want to implement two structs, Vector and Normal (this is because standard vectors and normal vectors map through certain transformations differently). I've implemented the following trait:

trait Components {
  fn new(x: f32, y: f32, z: f32) -> Self;
  fn x(&self) -> f32;
  fn y(&self) -> f32;
  fn z(&self) -> f32;
}

我还想将两个向量和两个法线相加,所以我有如下所示的块:

I'd also like to be add two vectors together, as well as two normals, so I have blocks that look like this:

impl Add<Vector> for Vector {
  type Output = Vector;
  fn add(self, rhs: Vector) -> Vector {
    Vector { vals: [
      self.x() + rhs.x(), 
      self.y() + rhs.y(), 
      self.z() + rhs.z()] }
  }
}

对于Normal来说几乎完全相同的impl.我真正想要的是为每个实现 Components 的结构提供一个默认的 Add impl,因为通常,它们都会以相同的方式添加(例如,第三个结构称为 >Point 会做同样的事情).除了为 PointVectorNormal 写出三个相同的实现之外,还有什么方法可以做到这一点?可能看起来像这样:

And almost the exact same impl for Normals. What I really want is to provide a default Add impl for every struct that implements Components, since typically, they all will add the same way (e.g. a third struct called Point will do the same thing). Is there a way of doing this besides writing out three identical implementations for Point, Vector, and Normal? Something that might look like this:

impl Add<Components> for Components {
  type Output = Components;
  fn add(self, rhs: Components) -> Components {
    Components::new(
      self.x() + rhs.x(), 
      self.y() + rhs.y(), 
      self.z() + rhs.z())
  }
}

其中Components"将自动被适当的类型替换.我想我可以在宏中做到这一点,但这对我来说似乎有点麻烦.

Where "Components" would automatically get replaced by the appropriate type. I suppose I could do it in a macro, but that seems a little hacky to me.

推荐答案

在 Rust 中,可以定义通用的 impl ,但是有一些重要的限制来自于一致性规则.你想要一个像这样的 impl:

In Rust, it is possible to define generic impls, but there are some important restrictions that result from the coherence rules. You'd like an impl that goes like this:

impl<T: Components> Add<T> for T {
  type Output = T;
  fn add(self, rhs: T) -> T {
    T::new(
      self.x() + rhs.x(), 
      self.y() + rhs.y(), 
      self.z() + rhs.z())
  }
}

不幸的是,这不能编译:

Unfortunately, this does not compile:

错误:类型参数 T 必须用作某些本地类型的类型参数(例如 MyStruct);只能为类型参数实现当前 crate 中定义的特征 [E0210]

error: type parameter T must be used as the type parameter for some local type (e.g. MyStruct<T>); only traits defined in the current crate can be implemented for a type parameter [E0210]

为什么?假设您的 Components 特性是公开的.现在,另一个 crate 中的类型可以实现 Components 特性.该类型也可能尝试实现 Add 特性.谁的 Add 实现应该获胜,你的包还是其他包的?根据 Rust 当前的一致性规则,另一个 crate 获得此特权.

Why? Suppose your Components trait were public. Now, a type in another crate could implement the Components trait. That type might also try to implement the Add trait. Whose implementation of Add should win, your crate's or that other crate's? By Rust's current coherence rules, the other crate gets this privilege.

目前,除了重复 impl 之外,唯一的选择是使用宏.Rust 的标准库在很多地方都使用了宏来避免重复 impls(特别是对于原始类型),所以你不必觉得脏!:P

For now, the only option, besides repeating the impls, is to use a macro. Rust's standard library uses macros in many places to avoid repeating impls (especially for the primitive types), so you don't have to feel dirty! :P

这篇关于为自定义特征提供一揽子特征实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆