gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-29 08:25:08 30 4
gpt4 key购买 nike

我正在尝试实现一个基本的 ECS在 rust 中。我想要一个数据结构,为每个组件存储该特定组件的存储。因为有些组件很常见而有些组件很少见,所以我想要不同类型的存储策略,例如 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>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从中?

做这一切的全部目的是我希望组件在内存中是连续的,并且每个组件类型都有不同的存储空间。我无法解决自己使用 Box<Component> ,否则我不知道该怎么做。

我将我的问题减少到最少的代码 on Rust Playground .

最佳答案

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

  1. 特质AnyStorage在你的例子中没有实现 ComponentStorage<T> ,因此因为您将“存储”存储在 HashMap<TypeId, Box<AnyStorage>> 中, Rust 不能保证每个存储类型都实现了 ComponentStorage<T>::insert()因为它只知道它们是 AnyStorage s.
  2. 如果你确实将这两个特征组合成一个简单地称为 Storage<T> 的特征并将它们存储在 HashMap<TypeId, Box<Storage<T>> 中, 每个版本 Storage由于单个 T 必须存储相同的类型. Rust 没有办法根据键的 TypeId 动态键入映射的值,因为这样的解决方案需要。此外,您不能替换 TAny因为Any不是 Sized ,这Vec和所有其他存储类型都需要。我猜您知道所有这些,这就是为什么您在原始示例中使用了两个不同的特征。

我最终使用的解决方案存储了 Storage<T>作为 Any s 在 HashMap<TypeId, Box<Any>> , 然后我沮丧了 Any进入Storage<T> s 在 StorageMgr 的实现函数中.我在下面放了一个简短的例子,完整版本在 Rust Playground here.

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!(),
}
}
}

关于rust - 在 Rust 中存储具有泛型类型参数的异构类型集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48327964/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com