trait 对象和 trait 的直接实现者的 trait 实现 [英] Trait implementation for both a trait object and for direct implementors of the trait
问题描述
我有一个主要封装向量的结构:
I have a struct that mostly encapsulates a vector:
struct Group<S> {
elements: Vec<S>
}
我还有一个简单的 trait,它也为其他结构体实现了:
I also have a simple trait which is also implemented for other structs:
trait Solid {
fn intersect(&self, ray: f32) -> f32;
}
我想为 Group
实现 Solid
,但我希望能够将 Group
都用于 Group
的相同实现的列表code>Solid 和 Solid
的混合实现列表.基本上我想同时使用 Group<Box<Solid>>
和 Group
Sphere
实现 Solid
>).
I want to implement Solid
for Group
, but I want to be able to use Group
both for lists of the same implementation of Solid
and for lists of mixed implementations of Solid
. Basically I want to use both Group<Box<Solid>>
and Group<Sphere>
(Sphere
implements Solid
).
目前我正在使用这样的东西:
Currently I am using something like this:
impl Solid for Group<Box<Solid>> {
fn intersect(&self, ray: f32) -> f32 {
//do stuff
}
}
impl<S: Solid> Solid for Group<S> {
fn intersect(&self, ray: f32) -> f32 {
//do the same stuff, code copy-pasted from previous impl
}
}
这行得通,但是将相同的代码逐行放置两次不是惯用的解决方案.我一定遗漏了一些明显的东西?
This works, but having line-for-line the same code twice can't be the idiomatic solution. I must be missing something obvious?
在我的例子中,我测量了两种 trait 实现之间的显着性能差异,因此总是使用 Group
并不是一个好的选择.
In my case I measure a notable performance difference between both trait implementations, so always using Group<Box<Solid>>
isn't a great option.
推荐答案
为所有 Box
实现你的 trait,其中 S
实现了你的 trait.然后你可以委托给现有的实现:
Implement your trait for all Box<S>
where S
implements your trait. Then you can delegate to the existing implementation:
impl<S: Solid + ?Sized> Solid for Box<S> {
fn intersect(&self, ray: f32) -> f32 {
(**self).intersect(ray)
// Some people prefer this less-ambiguous form
// S::intersect(self, ray)
}
}
您还会发现对引用执行相同操作也很有用:
You'll also find that it can be useful to do the same for references:
impl<S: Solid + ?Sized> Solid for &'_ S {
fn intersect(&self, ray: f32) -> f32 {
(**self).intersect(ray)
// Some people prefer this less-ambiguous form
// S::intersect(self, ray)
}
}
一起:
trait Solid {
fn intersect(&self, ray: f32) -> f32;
}
impl<S: Solid + ?Sized> Solid for Box<S> {
fn intersect(&self, ray: f32) -> f32 {
(**self).intersect(ray)
// S::intersect(self, ray)
}
}
impl<S: Solid + ?Sized> Solid for &'_ S {
fn intersect(&self, ray: f32) -> f32 {
(**self).intersect(ray)
// S::intersect(self, ray)
}
}
struct Group<S>(Vec<S>);
impl<S: Solid> Solid for Group<S> {
fn intersect(&self, _ray: f32) -> f32 {
42.42
}
}
struct Point;
impl Solid for Point {
fn intersect(&self, _ray: f32) -> f32 {
100.
}
}
fn main() {
let direct = Group(vec![Point]);
let boxed = Group(vec![Box::new(Point)]);
let pt = Point;
let reference = Group(vec![&pt]);
let mixed: Group<Box<dyn Solid>> = Group(vec![
Box::new(direct),
Box::new(boxed),
Box::new(Point),
Box::new(reference),
]);
mixed.intersect(1.0);
}
?Sized
绑定允许 S
在编译时没有已知的大小.重要的是,这允许您传入 trait 对象,例如 Box
或 &dyn Solid
作为类型 Solid
没有已知大小.
The ?Sized
bound allows the S
to not have a size known at compile time. Importantly, this allows you to pass in trait objects such as Box<dyn Solid>
or &dyn Solid
as the type Solid
does not have a known size.
另见:
这篇关于trait 对象和 trait 的直接实现者的 trait 实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!