我有一个trait Surface: 'static
,我想为struct Obj<'a>
实现。特征需要是'static
因为我想在Surface
中存储来自Vec<Box<Surface>>
类型的对象。
在第一步中我尝试了这个。
impl<'a> Surface for Obj<'a> {}
由于'static
和'a
之间的终身不匹配,这不起作用。换句话说:Surface
可以比Obj
更长寿,因为Surface
是'static
。我改变了我的实现如下。
impl<'a> Surface for Obj<'a> where 'a: 'static {}
据我正确理解文档,我正在做的是,'a
可以比'static
更长寿。我想要这个吗?
如果我转移Obj<'a>
的所有权,编译器会告诉我Obj
中的可变引用将不会存活足够长并仍然借用。
这是一个简短的例子。
trait Surface: 'static {}
struct Manager {
storage: Vec<Box<Surface>>,
}
impl Manager {
fn add(&mut self, surface: impl Surface) {
self.storage.push(Box::new(surface));
}
}
struct SomeOtherStruct {}
struct Obj<'a> {
data: &'a mut SomeOtherStruct,
}
impl<'a> Obj<'a> {
fn new(some_struct: &'a mut SomeOtherStruct) -> Self {
Obj { data: some_struct }
}
}
impl<'a> Surface for Obj<'a> where 'a: 'static {}
fn main() {
let mut some_struct = SomeOtherStruct {};
let mut manager = Manager {
storage: Vec::new(),
};
let obj = Obj::new(&mut some_struct);
manager.add(obj);
}
(Qazxswpoi)
Playground
换句话说,error[E0597]: `some_struct` does not live long enough
--> src/main.rs:33:24
|
33 | let obj = Obj::new(&mut some_struct);
| ---------^^^^^^^^^^^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `some_struct` is borrowed for `'static`
34 | manager.add(obj);
35 | }
| - `some_struct` dropped here while still borrowed
是终身&mut some_struct
但需要'a
。好吧很明显,因为'static
住在some_struct
所以它不能是Obj<'a>
?
这就是我想要做的“Rust like”吗?我不知道如何让它发挥作用。它的生命时间真的令人困惑。我想我可以通过使用'static
解决这个问题,但这会使事情变得更复杂。
如何使用
Rc<T>
生命周期为具有生命周期'static
的结构实现特征?
你不能也不能。 'a
一生的目的是说“在整个计划期间生活的东西”。除'static
本身外,没有任意生命'a
符合此要求。
首先要做的事情:
'static
很啰嗦
impl<'a> Surface for Obj<'a> where 'a: 'static {}
您正确识别了问题:
换句话说,
impl Surface for Obj<'static> {}
是终身&mut some_struct
但需要'a
你需要将'static
声明为some_struct
:
static
问题是,你不能安全地访问可变的静态变量,因为它们可以同时被多个线程变异,这是一个问题,因此你需要fn main() {
static mut SOME_STRUCT: SomeOtherStruct = SomeOtherStruct {};
// ...
let obj = unsafe { Obj::new(&mut SOME_STRUCT) };
// ...
}
。
所以不,你的代码不是“Rust like”,但我担心你不能用你当前的架构来改变它。
特征需要是'静态的,因为我想在
unsafe
中存储来自Surface
类型的对象。
我不明白为什么你认为你首先需要Vec<Box<Surface>>
,例如这段代码完全合法:
'static
trait Foo {}
struct Bar;
impl Foo for Bar {}
fn main() {
let b: Box<Foo> = Box::new(Bar);
}
工作并解决了我的问题,但它感觉hacky和反对Rust。
有了你的提示,我找到了一个更好的解决方案,alsos工作,不使用@hellow's answer。
解决方案1
我为unsafe
和Manager
类型指定了显式生命周期参数:
Box<Surface + 'a>
(Qazxswpoi)
解决方案2
在trait Surface {}
struct Manager<'a> {
storage: Vec<Box<Surface + 'a>>,
}
impl<'a> Manager<'a> {
fn add(&mut self, surface: impl Surface + 'a) {
self.storage.push(Box::new(surface));
}
}
struct SomeOtherStruct {}
struct Obj<'a> {
data: &'a mut SomeOtherStruct,
}
impl<'a> Obj<'a> {
fn new(some_struct: &'a mut SomeOtherStruct) -> Self {
Obj {
data: some_struct
}
}
}
impl<'a> Surface for Obj<'a> {}
fn main() {
let mut some_struct = SomeOtherStruct{};
let mut manager = Manager { storage: Vec::new() };
let obj = Obj::new(&mut some_struct);
manager.add(obj);
}
存储Playground而不是Box<SomeOtherStruct>
。这将消除生命周期:
&mut SomeOtherStruct
(Qazxswpoi)
在我看来,两种解决方案都很好。我不知道哪种解决方案更好,而且我没有这种解决方案的优缺点经验。对我来说(可能是因为我是初学者并且仍然倾向于Rust),更容易避免生命和使用Obj
,trait Surface {}
struct Manager {
storage: Vec<Box<Surface>>,
}
impl Manager {
fn add(&mut self, surface: impl Surface + 'static) {
self.storage.push(Box::new(surface));
}
}
struct SomeOtherStruct {}
struct Obj {
data: Box<SomeOtherStruct>,
}
impl Obj {
fn new(some_struct: Box<SomeOtherStruct>) -> Self {
Obj {
data: some_struct
}
}
}
impl Surface for Obj {}
fn main() {
let some_struct = SomeOtherStruct{};
let mut manager = Manager { storage: Vec::new() };
let obj = Obj::new(Box::new(some_struct));
manager.add(obj);
}
等。