具有不带 "self" 作为参数的函数的特征不能成为对象

Trait with function without "self" as parameter cannot be made into an object

作为我学习 Rust 之旅的一部分,我正在尝试构建一个实体组件系统。 我有一个想法,每个组件都有一个静态 ID,对象会有一个它包含的组件的 HashMap(每种类型限制一个组件)。

这是对象本身:

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 参数

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

大多数问题都可以通过遵循编译器消息轻松修复。

我在尝试编译您的代码时遇到的最大障碍是

这是我的尝试,我不知道它最终是否真的做了什么,但至少它编译了:)

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,因为这可能是您真正想要的。
  • add_component
  • 中将 mut 添加到 self
  • 删除 id() 的默认实现以实际强制实现结构覆盖它
  • 基于 ,将 &dyn Component 向下转换为 get_component 中的实际组件类型。当然可能有不同的解决方案,我只是选择了那个,因为我不想做任何进一步的研究:)

我没有解决您目前只能从 get_component 中获取 non-mutable 个对象的问题。这可能是您接下来要解决的问题。

总而言之,这是您的代码的一个最小工作示例,其中包含“姓名”和“年龄”组件,只是为了证明您的方法是可行的:

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