我有一个要为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);
}
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>
中,所以它不可能是'static
吗?
这是我要做的“ Rust like”吗?我不知道如何使它工作。它的确与生命周期混淆。我想我可以使用Rc<T>
来解决这个问题,但这会使事情变得更复杂。
答案 0 :(得分:3)
第一件事:
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) };
// ...
}
问题是,您不能安全地访问可变静态变量,因为它们可以同时在多线程中进行变异,这是一个问题,因此您需要unsafe
。
所以不,您的代码不是“ Rust like”,但恐怕您无法用当前的体系结构进行更改。
特质必须是“静态的,因为我想将
Surface
类型的对象存储在Vec<Box<Surface>>
中。
我不明白为什么您首先认为需要'static
,例如该代码完全合法:
trait Foo {}
struct Bar;
impl Foo for Bar {}
fn main() {
let b: Box<Foo> = Box::new(Bar);
}
答案 1 :(得分:2)
如何为寿命为
'static
的结构实现寿命为'a
的特征?
您没有,也没有。 'static
生命周期的目的是说“在程序的整个过程中都存在的东西”。除了{em> 'a
本身之外,没有任意生存期'static
满足此要求。
答案 2 :(得分:1)
@hellow's answer可以解决我的问题,但是对Rust来说,这很hacky。
在您的提示下,我找到了一种更好的解决方案,该解决方案也可以使用并且不使用unsafe
。
解决方案1
我为Manager
和类型Box<Surface + 'a>
指定了明确的生存期参数:
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);
}
解决方案2
在Box<SomeOtherStruct>
中存储&mut SomeOtherStruct
而不是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);
}
我认为这两种解决方案都不错。我不知道哪种解决方案更好,并且我对这种解决方案的优缺点也没有经验。
对我来说(也许是因为我是一个初学者,并且仍然偏爱Rust)所以避免寿命和使用Box
,Rc
等更容易。