为什么以下示例中的不可变版本可以工作,但可变版本无法编译并出现错误
error: lifetime may not live long enough
?
trait Car {
fn honk(&self);
}
struct CarCollection {
cars: HashMap<usize, Box<dyn Car>>,
}
impl CarCollection {
// Does compile
fn get(&self, id: usize) -> Option<&dyn Car> {
self.cars.get(&id).map(|c| c.as_ref())
}
// Does not compile
fn get_mut(&mut self, id: usize) -> Option<&mut dyn Car> {
self.cars.get_mut(&id).map(|c| c.as_mut())
}
}
我知道我可以通过以下方式解决这个问题:
if let Some(car) = self.cars.get_mut(id) {
Some(car.as_mut())
} else {
None
}
尽管如此,我对此感到非常困惑,想知道这是怎么回事?我认为可变引用和不可变引用之间的生命周期没有区别。
这与 trait 对象生命周期省略规则有关。
struct CarCollection {
cars: HashMap<usize, Box<dyn Car>>,
}
这里,省略规则导致了这个隐含的生命周期:
struct CarCollection {
cars: HashMap<usize, Box<dyn Car + 'static>>,
}
现在我们来看看这个方法:
fn get_mut(&mut self, id: usize) -> Option<&mut dyn Car>
当我们对省略的引用生命周期进行脱糖处理时,我们得到:
fn get_mut<'a>(&'a mut self, id: usize) -> Option<&'a mut dyn Car>
然后,根据特征对象生命周期省略规则,我们得到这样的结果:
fn get_mut<'a>(&'a mut self, id: usize) -> Option<&'a mut (dyn Car + 'a)>
当您尝试返回
&mut (dyn Car + 'static)
时,这会导致生命周期不匹配。 这在共享引用情况下有效,因为共享引用的生命周期可以隐式缩短,但独占引用何时发生这种情况的规则通常不允许这样做。
通过显式设置特征对象的生命周期,可以轻松解决这种情况下的问题
'static
:
fn get_mut(&mut self, id: usize) -> Option<&mut (dyn Car + 'static)>