英文:
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(&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
}
}
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<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
}
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<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
}
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
的嵌套类型。
这个实现看起来有点奇怪,因为一个并不实际属于类型的泛型,所以你需要将HasPos
的T
转换为关联类型,如下所示:
#![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()
}
}
需要注意的是:现在你永远不能为同一类型手动实现HasShape
和HasPos
。
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<T: HasPos<T>> 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<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()
}
}
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(&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`
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(&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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论