在async函数中使用非Sync的HashMap遇编译错误
问题解决:避免DiffVoxelRepository的Sync要求
错误原因分析
你遇到的编译错误源于async_trait库的默认行为:它会强制生成的Future实现Send trait。对于get方法中的异步块来说,它捕获了&self引用,而&T要实现Send的前提是T必须实现Sync。但你的DiffVoxelRepository包含HashMap,标准库的HashMap并未实现Sync(其内部数据结构不支持多线程下的无锁共享访问),这导致DiffVoxelRepository不满足Sync,进而&DiffVoxelRepository不满足Send,最终异步块生成的Future也无法满足Send要求。
解决方案:使用async_trait的非Send变体
既然代码只在单线程环境运行,完全不需要Future具备Send能力。可以通过#[async_trait(?Send)]替代默认的#[async_trait],告诉库不要强制生成的Future实现Send。
修改后的代码
use std::{marker::PhantomData, collections::HashMap}; use async_trait::async_trait; #[derive(PartialEq, Eq, Hash)] struct IVec3 { pub x: i32, pub y: i32, pub z: i32 } trait VoxelComponent : Copy + Send {} enum VoxelRepositoryError{} // 使用?Send标记,不强制Future为Send #[async_trait(?Send)] trait VoxelRepository<T: VoxelComponent> : Send { async fn get(&self, position: IVec3) -> Result<Option<T>, VoxelRepositoryError>; async fn set(&mut self, position: IVec3, component: Option<T>) -> Result<(), VoxelRepositoryError>; } struct DiffVoxelRepository<R: VoxelRepository<C>, C: VoxelComponent> { source_repository: R, cache: HashMap<IVec3, C>, _component: PhantomData<fn() -> C> } impl<R: VoxelRepository<C>, C: VoxelComponent> DiffVoxelRepository<R, C> { fn new(repository: R) -> DiffVoxelRepository<R, C> { DiffVoxelRepository { source_repository: repository, cache: HashMap::new(), _component: PhantomData } } } // 同样使用?Send标记 #[async_trait(?Send)] impl<R: VoxelRepository<C>, C: VoxelComponent> VoxelRepository<C> for DiffVoxelRepository<R, C> { async fn get(&self, position: IVec3) -> Result<Option<C>, VoxelRepositoryError> { match self.cache.get(&position) { Some(value) => Ok(Some(*value)), None => self.source_repository.get(position).await } } async fn set(&mut self, position: IVec3, component: Option<C>) -> Result<(), VoxelRepositoryError>{ match component { Some(c) => self.cache.insert(position, c), None => self.cache.remove(&position) }; self.source_repository.set(position, component).await } }
方案说明
#[async_trait(?Send)]会调整async_trait生成的代码,不再要求异步方法返回的Future实现Send。这样即使&DiffVoxelRepository不满足Send(因为结构体本身不是Sync),也不会触发编译错误——单线程运行时根本不需要跨线程传递Future。
这个方案既避免了使用Mutex带来的不必要开销,又完全符合你只在单线程运行的需求。
内容的提问来源于stack exchange,提问作者Rick de Water
相关产品推荐
相关产品推荐

