做一个通用的trait持有的东西实现一个单独的trait?



我有一个trait确保无论实现什么结构它都包含特定的数据类型所以我可以在任何实现trait的地方使用这些结构,

trait HasShape{
fn ref_vertices(&self) -> &Vec<Vertex>;
fn ref_vbo(&self) -> &VertexBuffer<Vertex>;
// Goes on for the rest of the trait
}
trait Drawable
{
fn draw(&self, target: &Frame);
}
impl<T> Drawable for T
where T: HasShape
{
fn draw(&self, target: &Frame) {
let vertices = self.ref_vertices();
// Use the fields on type that are required by HasShape
}
}

我还有另一个类似的trait但是它需要包含一个实现HasShape和其他字段的对象

trait HasPos<T>
where
T: HasShape
{
fn ref_shape(&self) -> &T;
fn ref_pos(&self) -> &Vector2f32;
// Rest is the same style as HasShape
}
trait Manipulate<T>
where T: HasShape
{
fn translate(&self, x: f32, y: f32);
// Rest are similar functions that change the fields of HasPos
}

我的问题是,我如何为所有具有HasPos的类型实现HasShape,以便我可以使用任何实现HasPos的HasShape对象?这样的

impl<T: HasPos<T>> HasShape for T
where T: HasShape
{
fn ref_vertices(&self) -> &Vec<Vertex>{
self.ref_shape().ref_vertices()
}
// Every function in HasShape just gets the field from the object in HasPos
}

这样我就可以调用函数从Drawable上实现HasPos的任何对象,以及?

impl<T: HasPos<T>> HasShape for T
where T: HasShape

这没有多大意义;您正在为已经实现HasShape的所有类型实现HasShape

如果我理解正确的话,您希望为已经实现HasPos的所有对象自动实现HasShape。如果是这样,你实际上有两个泛型;一个用于您想要实现HasShape的对象,另一个用于HasPos的嵌套类型。

对于实际上不是类型一部分的泛型,impl有点奇怪,所以您需要将HasPosT转换为相关类型,如下所示:

#![allow(unused_variables)]
use std::marker::PhantomData;
pub struct Frame;
pub struct Vertex;
pub struct VertexBuffer<B>(PhantomData<B>);
pub struct Vector2f32;
trait HasShape {
fn ref_vertices(&self) -> &Vec<Vertex>;
fn ref_vbo(&self) -> &VertexBuffer<Vertex>;
// Goes on for the rest of the trait
}
trait Drawable {
fn draw(&self, target: &Frame);
}
impl<T> Drawable for T
where
T: HasShape,
{
fn draw(&self, target: &Frame) {
let vertices = self.ref_vertices();
// Use the fields on type that are required by HasShape
}
}
trait HasPos {
type Shape: HasShape;
fn ref_shape(&self) -> &Self::Shape;
fn ref_pos(&self) -> &Vector2f32;
// Rest is the same style as HasShape
}
trait Manipulate<T>
where
T: HasShape,
{
fn translate(&self, x: f32, y: f32);
// Rest are similar functions that change the fields of HasPos
}
impl<T> HasShape for T
where
T: HasPos,
{
fn ref_vertices(&self) -> &Vec<Vertex> {
self.ref_shape().ref_vertices()
}
fn ref_vbo(&self) -> &VertexBuffer<Vertex> {
self.ref_shape().ref_vbo()
}
}

请注意,这里有一个警告:现在您永远不能为同一类型手动实现HasShapeHasPos

struct MyType;
impl HasPos for MyType {
type Shape = MyType;
fn ref_shape(&self) -> &Self::Shape {
todo!()
}
fn ref_pos(&self) -> &Vector2f32 {
todo!()
}
}
impl HasShape for MyType {
fn ref_vertices(&self) -> &Vec<Vertex> {
todo!()
}
fn ref_vbo(&self) -> &VertexBuffer<Vertex> {
todo!()
}
}
error[E0119]: conflicting implementations of trait `HasShape` for type `MyType`
--> src/lib.rs:73:1
|
46 | impl<T> HasShape for T
| ---------------------- first implementation here
...
73 | impl HasShape for MyType {
| ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyType`

这也意味着没有HasShape可以将自己作为HasPos类型,因为这会创建一个无限递归:

struct MyType;
impl HasPos for MyType {
type Shape = MyType;
fn ref_shape(&self) -> &Self::Shape {
&self
}
fn ref_pos(&self) -> &Vector2f32 {
todo!()
}
}
fn main() {
let x = MyType;
x.ref_vertices();
}
thread 'main' has overflowed its stack
fatal runtime error: stack overflow
Aborted

最新更新