具有“自我quot”的功能的特征因为不能将参数制成对象

发布于 2025-01-24 01:40:52 字数 1042 浏览 2 评论 0 原文

我正在尝试建立一个实体组件系统,以作为我学习生锈的旅程的一部分。 我知道每个组件在哪里具有静态ID,并且对象将具有其中包含的组件的缩放图(每种类型的一个组件的限制)。

这是对象本身:

pub struct Object {
    // TODO : components !
    components: HashMap<i32, Box<dyn Component>>
}

impl Object {
    pub fn add_component<C: Component>(&self) {
        self.components.insert(C::id(), Box::new(C::new()));
    }

    pub fn get_component<C: Component>(&self) -> Option<&C> {
        return self.components.get(C::id())
    }
}

这是我的组件特征:

pub trait Component {
    fn id() -> i32 {
        // one must ensure this returns different id for every component
        return 0;
    }

    fn new<C: Component>() -> C;

    fn require_rendering(&self) -> bool {
        return false;
    }

    fn some_function_on_component(&mut self) {
        // do something on the component 
    }
}

不幸的是,我得到此错误: “这个特征不能成为对象... ...因为关联的函数 id 没有 self 参数“

谁能解释为什么这不起作用,以及如何处理它?

I am trying to build a entity component system as part of my journey to learn Rust.
I had an idea where each component would have a static id, and objects would have a HashMap of the components it contains (with the limit of one component per type).

Here is the object itself:

pub struct Object {
    // TODO : components !
    components: HashMap<i32, Box<dyn Component>>
}

impl Object {
    pub fn add_component<C: Component>(&self) {
        self.components.insert(C::id(), Box::new(C::new()));
    }

    pub fn get_component<C: Component>(&self) -> Option<&C> {
        return self.components.get(C::id())
    }
}

And here is my Component trait:

pub trait Component {
    fn id() -> i32 {
        // one must ensure this returns different id for every component
        return 0;
    }

    fn new<C: Component>() -> C;

    fn require_rendering(&self) -> bool {
        return false;
    }

    fn some_function_on_component(&mut self) {
        // do something on the component 
    }
}

Unfortunately, I get this error :
"this trait cannot be made into an object...
...because associated function id has no self parameter"

Could anyone explain why does this not work, and how to work around it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

紫瑟鸿黎 2025-01-31 01:40:52

通过遵循编译器消息,大多数可以很容易地解决。

我在试图将代码编译时遇到的最大障碍是降低 box&lt; dyn&gt; 回到其原始类型

那是我的尝试,我不知道它是否最终是否确实在做某事,但至少它编译了:)

use std::any::Any;
use std::collections::HashMap;

pub struct Object {
    // TODO : components !
    components: HashMap<i32, Box<dyn Component>>,
}

impl Object {
    pub fn new() -> Self {
        Self {
            components: HashMap::new(),
        }
    }

    pub fn add_component<C: 'static + Component>(&mut self) {
        self.components.insert(C::id(), Box::new(C::new()));
    }

    pub fn get_component<C: 'static + Component>(&self) -> Option<&C> {
        self.components
            .get(&C::id())
            .map(|boxed_component| boxed_component.as_any().downcast_ref::<C>().unwrap())
    }
}

pub trait Component {
    fn id() -> i32
    where
        Self: Sized;

    fn new() -> Self
    where
        Self: Sized;

    fn require_rendering(&self) -> bool {
        return false;
    }

    fn some_function_on_component(&mut self) {
        // do something on the component
    }

    fn as_any(&self) -> &dyn Any;
}

我已经完成的事情:

  • 添加 self:sized id() new()。这两个都是性状函数,因此必须在运行时解决。解决类型的步骤需要称为“ vtable”的东西,这仅存在于实际尺寸的类型上。 (至少这是我对问题的理解)
  • new 上的 self 替换通用参数,因为这是您实际上想要的。
  • mut 添加到 self in add_component
  • 删除 id> id()的默认实现,以实际强制实现结构来覆盖其降低
  • 其垂直基于 get_component &amp; dyn Component ,基于此帖子。当然,可能有不同的解决方案,我只是选择了一个,因为我不想做任何进一步的研究:)

我没有解决您目前只从 get_component 。这可能是您将要解决的下一步。

总而言之,这是带有“名称”和“年龄”组件的代码的最小工作示例,只是为了证明您的方法是可行的:

Most of those are fairly easily fixable by following the compiler messages.

The biggest hurdle I came across while trying to get your code to compile is to downcast the Box<dyn> back to its original type.

That's my attempt, I have no idea if it actually does something in the end, but at least it compiles :)

use std::any::Any;
use std::collections::HashMap;

pub struct Object {
    // TODO : components !
    components: HashMap<i32, Box<dyn Component>>,
}

impl Object {
    pub fn new() -> Self {
        Self {
            components: HashMap::new(),
        }
    }

    pub fn add_component<C: 'static + Component>(&mut self) {
        self.components.insert(C::id(), Box::new(C::new()));
    }

    pub fn get_component<C: 'static + Component>(&self) -> Option<&C> {
        self.components
            .get(&C::id())
            .map(|boxed_component| boxed_component.as_any().downcast_ref::<C>().unwrap())
    }
}

pub trait Component {
    fn id() -> i32
    where
        Self: Sized;

    fn new() -> Self
    where
        Self: Sized;

    fn require_rendering(&self) -> bool {
        return false;
    }

    fn some_function_on_component(&mut self) {
        // do something on the component
    }

    fn as_any(&self) -> &dyn Any;
}

Things I've done:

  • Add Self: Sized to id() and new(). Both of those are trait functions and therefore have to be resolved at runtime. The step of resolving the type requires something called a "vtable", which only exists on types that actually have a size. (that's at least my understanding of the problem)
  • Replace the generic parameter on new with Self, as this is what you probably actually want.
  • Add mut to self in add_component
  • Remove default implementation of id() to actually force implementing structs to overwrite it
  • Downcast the &dyn Component to the actual component type in get_component, based on this post. Of course there are probably different solutions, I just picked that one because I didn't feel like doing any further research :)

I didn't solve the problem that you currently only get non-mutable objects out of get_component. This will probably be the next thing you will tackle.

All in all, here is a minimal working example of your code with a "Name" and an "Age" component, just to demonstrate that your approach is feasible:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=5d22b64ab924394606a07a043594f608

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文