在Rust中存储具有泛型类型参数的异构类型集合
我正在尝试在Rust中实现一个基本功能。我想要一个数据结构,为每个组件存储一个特定组件的存储器。由于某些组件是通用的,而其他组件是稀有的,因此我需要不同类型的存储策略,例如在Rust中存储具有泛型类型参数的异构类型集合,rust,Rust,我正在尝试在Rust中实现一个基本功能。我想要一个数据结构,为每个组件存储一个特定组件的存储器。由于某些组件是通用的,而其他组件是稀有的,因此我需要不同类型的存储策略,例如VecStorage和HashMapStorage 由于游戏引擎的ECS不知道组件,我想到了: trait AnyStorage: Debug { fn new() -> Self where Self: Sized; } #[derive(Default, Debug)] struct
VecStorage
和HashMapStorage
由于游戏引擎的ECS不知道组件,我想到了:
trait AnyStorage: Debug {
fn new() -> Self
where
Self: Sized;
}
#[derive(Default, Debug)]
struct StorageMgr {
storages: HashMap<TypeId, Box<AnyStorage>>,
}
我知道我的问题来自这样一个事实,
存储
的类型是&mut-Box。我不确定这样的事情是否可能发生,但我终于找到了答案。关于您发布的示例失败的原因,有几点需要注意
TraitAnyStorage
在您的示例中没有实现ComponentStorage
,因此,因为您将“存储”存储在哈希映射中
哪里
自我:大小;
fn插入(&mut self,值:T);
}
结构存储管理器{
存储:HashMap,
}
impl-StorageMgr{
pub fn new()->Self{
自我{
存储:HashMap::new(),
}
}
pub fn get_storage_mut(&mut self)->&mut::storage{
让type_id=TypeId::of::();
//如果存储尚不存在,请添加存储
if!self.storages.包含\u键(&键入\u id){
让新存储=::存储::新();
self.storages.insert(type_id,Box::new(new_storage));
}
//获取此类型的存储空间
匹配self.storages.get_mut(&type_id){
一些(可能是_存储)=>{
//将Any转换为该类型的存储
可能与存储匹配。向下播放\u mut::(){
一些(存储)=>存储,
None=>unreachable!(),//unreachable!(),
}
}
}
请您的问题解释为什么它不是的副本。@Shepmaster,因为“generic”这个词。我知道如何创建异构集合以及如何在Rust中使用多态性,但不知道如何使用泛型。我是否应该将此作为介绍性段落添加?@ToToTorigolo这是不可能的。Trait对象不能具有泛型类型参数,因为这些参数是在编译时解析的。通常的解决方法是使用/操作c通过所有组件的另一个共同特征来定义对象。即,忽略异构性并使用具体类型(例如,每个类型有多个容器,或者组件有一个枚举类型)@E_net4谢谢你的澄清。但我意识到我问题的标题很不清楚。我想做的不是严格意义上的异构泛型集合:这就是从宏观角度看的StorageMgr
。(对不起,我说不清楚)我写了一个共同的特点,AnyStorage
,正如您所建议的,我确信有一种方法可以让我的VecStorage
返回,因为println!(“{:?}”,storage);
打印VecStorage([])
。只能这样做,因为您将Debug
约束添加到了AnyStorage
。听起来您希望在AnyStorage
中插入方法。
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>>();
}
trait Component: Debug + Sized + Any {
type Storage: Storage<Self>;
}
trait Storage<T: Debug>: Debug + Any {
fn new() -> Self
where
Self: Sized;
fn insert(&mut self, value: T);
}
struct StorageMgr {
storages: HashMap<TypeId, Box<Any>>,
}
impl StorageMgr {
pub fn new() -> Self {
Self {
storages: HashMap::new(),
}
}
pub fn get_storage_mut<C: Component>(&mut self) -> &mut <C as Component>::Storage {
let type_id = TypeId::of::<C>();
// Add a storage if it doesn't exist yet
if !self.storages.contains_key(&type_id) {
let new_storage = <C as Component>::Storage::new();
self.storages.insert(type_id, Box::new(new_storage));
}
// Get the storage for this type
match self.storages.get_mut(&type_id) {
Some(probably_storage) => {
// Turn the Any into the storage for that type
match probably_storage.downcast_mut::<<C as Component>::Storage>() {
Some(storage) => storage,
None => unreachable!(), // <- you may want to do something less explosive here
}
}
None => unreachable!(),
}
}
}