制作一个通用的特质,其中包含实现了另一个特质的内容?

huangapple go评论62阅读模式
英文:

Make a generic trait that holds something that implements a separate 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
    }
}

我还有另一个类似的特质,不过它需要包含一个实现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
}

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

英文:

I have a trait that makes sure whatever struct implements it holds specific data types so I can use those structs in any place where that trait is implemented,

trait HasShape{
    fn ref_vertices(&amp;self) -&gt; &amp;Vec&lt;Vertex&gt;;
    fn ref_vbo(&amp;self) -&gt; &amp;VertexBuffer&lt;Vertex&gt;;
    // Goes on for the rest of the trait
}

trait Drawable
{
    fn draw(&amp;self, target: &amp;Frame);
}

impl&lt;T&gt; Drawable for T
where T: HasShape
{
    fn draw(&amp;self, target: &amp;Frame) {
        let vertices = self.ref_vertices();
        // Use the fields on type that are required by HasShape
    }
}

And I have another trait that is similar however it needs to hold an object that implements HasShape as well as other fields

trait HasPos&lt;T&gt;
where
    T: HasShape
{
    fn ref_shape(&amp;self) -&gt; &amp;T;
    fn ref_pos(&amp;self) -&gt; &amp;Vector2f32;
    // Rest is the same style as HasShape
}

trait Manipulate&lt;T&gt;
where T: HasShape
{
    fn translate(&amp;self, x: f32, y: f32);
    // Rest are similar functions that change the fields of HasPos
}

My question is, how do I implement HasShape for all types that have HasPos so I can use anything that implements HasPos in place of a HasShape object?
like this

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

That way I can call functions from Drawable on any object that implements HasPos as well?

答案1

得分: 0

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

这个不太有意义;你正在为已经实现了HasShape的所有类型来实现HasShape

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

这个实现看起来有点奇怪,因为一个并不实际属于类型的泛型,所以你需要将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>;
    // 其余的特质内容
}

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();
        // 使用HasShape所需的类型字段
    }
}

trait HasPos {
    type Shape: HasShape;

    fn ref_shape(&self) -> &Self::Shape;
    fn ref_pos(&self) -> &Vector2f32;
    // 其余的特质内容
}

trait Manipulate<T>
where
    T: HasShape,
{
    fn translate(&self, x: f32, y: f32);
    // 其余的函数类似地更改了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
英文:
impl&lt;T: HasPos&lt;T&gt;&gt; HasShape for T
where T: HasShape

This doesn't make much sense; you are implementing HasShape for all types that already implement HasShape.

If I understand correctly, you want to auto-implement HasShape for all objects that already implement HasPos. If so, you actually have two generics; one for the object you want to implement HasShape for, and one for the nested type of HasPos.

The impl is a little weird with a generic that isn't actually part of the type, though, so you need to convert T of HasPos to an associated type, like so:

#![allow(unused_variables)]

use std::marker::PhantomData;

pub struct Frame;
pub struct Vertex;
pub struct VertexBuffer&lt;B&gt;(PhantomData&lt;B&gt;);
pub struct Vector2f32;

trait HasShape {
    fn ref_vertices(&amp;self) -&gt; &amp;Vec&lt;Vertex&gt;;
    fn ref_vbo(&amp;self) -&gt; &amp;VertexBuffer&lt;Vertex&gt;;
    // Goes on for the rest of the trait
}

trait Drawable {
    fn draw(&amp;self, target: &amp;Frame);
}

impl&lt;T&gt; Drawable for T
where
    T: HasShape,
{
    fn draw(&amp;self, target: &amp;Frame) {
        let vertices = self.ref_vertices();
        // Use the fields on type that are required by HasShape
    }
}

trait HasPos {
    type Shape: HasShape;

    fn ref_shape(&amp;self) -&gt; &amp;Self::Shape;
    fn ref_pos(&amp;self) -&gt; &amp;Vector2f32;
    // Rest is the same style as HasShape
}

trait Manipulate&lt;T&gt;
where
    T: HasShape,
{
    fn translate(&amp;self, x: f32, y: f32);
    // Rest are similar functions that change the fields of HasPos
}

impl&lt;T&gt; HasShape for T
where
    T: HasPos,
{
    fn ref_vertices(&amp;self) -&gt; &amp;Vec&lt;Vertex&gt; {
        self.ref_shape().ref_vertices()
    }

    fn ref_vbo(&amp;self) -&gt; &amp;VertexBuffer&lt;Vertex&gt; {
        self.ref_shape().ref_vbo()
    }
}

Note that there is one caveat, though: Now you can never manually implement HasShape and HasPos for the same type.

struct MyType;

impl HasPos for MyType {
    type Shape = MyType;

    fn ref_shape(&amp;self) -&gt; &amp;Self::Shape {
        todo!()
    }

    fn ref_pos(&amp;self) -&gt; &amp;Vector2f32 {
        todo!()
    }
}

impl HasShape for MyType {
    fn ref_vertices(&amp;self) -&gt; &amp;Vec&lt;Vertex&gt; {
        todo!()
    }

    fn ref_vbo(&amp;self) -&gt; &amp;VertexBuffer&lt;Vertex&gt; {
        todo!()
    }
}
error[E0119]: conflicting implementations of trait `HasShape` for type `MyType`
  --&gt; src/lib.rs:73:1
   |
46 | impl&lt;T&gt; HasShape for T
   | ---------------------- first implementation here
...
73 | impl HasShape for MyType {
   | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyType`

This also means that no HasShape can have itself as its HasPos type, because this will create an infinite recursion:

struct MyType;

impl HasPos for MyType {
    type Shape = MyType;

    fn ref_shape(&amp;self) -&gt; &amp;Self::Shape {
        &amp;self
    }

    fn ref_pos(&amp;self) -&gt; &amp;Vector2f32 {
        todo!()
    }
}

fn main() {
    let x = MyType;
    x.ref_vertices();
}
thread &#39;main&#39; has overflowed its stack
fatal runtime error: stack overflow
Aborted

huangapple
  • 本文由 发表于 2023年1月9日 00:48:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/75049617.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定