在Rust中存储具有泛型类型参数的异构类型的集合

时间:2018-01-18 18:25:21

标签: rust

我正在尝试在Rust中实现基本的ECS。我想要一个数据结构,为每个组件存储该特定组件的存储。由于某些组件很常见而其他组件很少,因此我需要不同类型的存储策略,例如VecStorage<T>HashMapStorage<T>

由于游戏引擎的ECS不知道组件,我想出了:

trait AnyStorage: Debug {
    fn new() -> Self
    where
        Self: Sized;
}

#[derive(Default, Debug)]
struct StorageMgr {
    storages: HashMap<TypeId, Box<AnyStorage>>,
}

VecStorageHashMapStorage<T>实施AnyStorage特征。由于AnyStorage不知道T,我添加了另外一个具体存储空间实现的特征:ComponentStorage<T>

虽然我能够注册新组件(即在Box<AnyStorage>的{​​{1}}中添加新的StorageMgr),但我找不到插入组件的方法。

这是错误的代码:

storages

我知道我的问题来自pub fn add_component_to_storage<C: Component>(&mut self, component: C) { let storage = self.storages.get_mut(&TypeId::of::<C>()).unwrap(); // storage is of type: &mut Box<AnyStorage + 'static> println!("{:?}", storage); // Prints "VecStorage([])" storage.insert(component); // This doesn't work // This neither: // let any_stor: &mut Any = storage; // let storage = any_stor.downcast_ref::<ComponentStorage<C>>(); } 的类型为storage的事实;我能从中获得具体的&mut Box<AnyStorage>吗?

完成所有这一切的重点在于我希望组件在内存中是连续的,并且每个组件类型都有不同的存储空间。我无法解决自己使用VecStorage,或者我不知道如何使用。

我将问题缩减为最小代码on Rust Playground

1 个答案:

答案 0 :(得分:3)

我不确定这样的事情是否可行,但我终于明白了。关于你发布的示例失败的原因,有几点需要注意。

  1. 示例中的特征AnyStorage未实现ComponentStorage<T>,因此您将“存储”存储在HashMap<TypeId, Box<AnyStorage>>中,Rust无法保证每个存储的类型都已实现{{ 1}}因为它只知道它们是ComponentStorage<T>::insert() s。
  2. 如果您确实将两个特征合并为一个简称为AnyStorage的特征并将其存储在Storage<T>中,则HashMap<TypeId, Box<Storage<T>>的每个版本都必须存储相同的类型,因为单{{ {1}}。 Rust没有办法根据键的TypeId动态键入映射的值,因为这样的解决方案需要。此外,您无法将Storage替换为T,因为T不是AnyAny和所有其他存储类型都需要。我猜你知道这一切,这就是为什么你在原始例子中使用了两个不同的特征。
  3. 我最终使用的解决方案将Sized s存储为Vec中的Storage<T>,然后我将Any下载到HashMap<TypeId, Box<Any>> s在Any的实现函数中。我在下面给出了一个简短的例子,完整版本在Rust Playground上here

    Storage<T>