对于上下文:我正在实现一个实体,基本上是围绕异构映射的薄包装,并试图实现一个update
方法:
struct Entity {
pub id: u64,
data: HashMap<TypeId, Box<dyn Any>>,
}
impl Entity {
pub fn new(id: u64) -> Self {
Entity { id, data: HashMap::new() }
}
pub fn get_atom<T: Any>(&self) -> Option<&T> {
self.data.get(&TypeId::of::<T>())?.downcast_ref()
}
pub fn set_atom<T: Any>(&mut self, value: T) {
self.data.insert(TypeId::of::<T>(), Box::new(value));
}
pub fn update<T: Any, R: Any>(&mut self, f: impl Fn(&T) -> R)
{
if let Some(val) = self.get_atom() {
self.set_atom(f(val));
}
}
}
这个可以工作,但是给出一个警告:
warning: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/entity.rs:71:13
|
70 | if let Some(val) = self.get_atom() {
| --------------- immutable borrow occurs here
71 | self.set_atom(f(val));
| ^^^^^^^^^^^^^^^^---^^
| | |
| | immutable borrow later used here
| mutable borrow occurs here
好的,这是可以修复的,这样就删除了警告。
pub fn update<T: Any, R: Any>(&mut self, f: impl Fn(&T) -> R)
{
let maybe : Option<R> = self.get_atom().map(f);
if let Some(val) = maybe {
self.set_atom(val);
}
}
我遇到的问题是,当我引入一个trait来抽象从实体中获取的东西时(这允许我抽象实体:如果每个组件都在实体中,则获得一个元组返回一个值):
trait GetComponent<'a, T> {
fn get_component(entity: &'a Entity) -> Option<T>;
}
// sample atom impl
impl <'a> GetComponent<'a, &'a u32> for &'a u32 {
fn get_component(entity: &'a Entity) -> Option<&'a u32> {
entity.get_atom()
}
}
// sample composite impl
impl <'a, A, B> GetComponent<'a, (A, B)> for (A, B) where
A: GetComponent<'a, A>,
B: GetComponent<'a, B>,
{
fn get_component(entity: &'a Entity) -> Option<(A, B)> {
Some((A::get_component(entity)?, B::get_component(entity)?))
}
}
impl Entity {
<in addition to the above>
pub fn get<'a, T: GetComponent<'a, T>>(&'a self) -> Option<T> {
T::get_component(self)
}
pub fn update<'a, T: 'a, R: Any>(&'a mut self, f: impl Fn(&T) -> R)
where &'a T: GetComponent<'a, &'a T>
{
let maybe : Option<R> = self.get().map(f);
if let Some(val) = maybe {
self.set_atom(val);
}
}
}
这个特性要求我明确生命周期,到目前为止,我对这个实体所做的一切似乎都很好。但是这个更新方法给出了以下编译错误(这次不是警告):
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/entity.rs:56:13
|
51 | pub fn update<'a, T: 'a, R: Any>(&'a mut self, f: impl Fn(&T) -> R)
| -- lifetime `'a` defined here
...
54 | let maybe : Option<R> = self.get().map(f);
| ----------
| |
| immutable borrow occurs here
| argument requires that `*self` is borrowed for `'a`
55 | if let Some(val) = maybe {
56 | self.set_atom(val);
| ^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
现在,据我所知,没有理由不能在较短的时间内不可变借用,所以不可变借用"到期"了;就像在性状之前没有显式生命周期的版本一样。
但是我无论如何也想不出该怎么做。
你可以用更高等级的特征界(HRTB)来解决这个问题:
pub fn update<T, R: Any>(&mut self, f: impl Fn(&T) -> R)
where for <'a> &'a T: GetComponent<'a, &'a T>
这说明对于任何可能的寿命'a
,T
必须满足给定的界。这允许您指定类型T
上的各种生命周期如何相互关联,而无需将它们绑定到特定的生命周期,例如&mut self
。 (游乐场)