如何为具有“a”生命周期的结构实现具有“静态生命周期”的特征?
How to implement a trait with 'static lifetime for a struct with lifetime 'a?
我有一个 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>
来解决这个问题,但这会使事情变得更复杂。
要事第一:
impl<'a> Surface for Obj<'a> where 'a: 'static {}
对于
来说是冗长的
impl Surface for Obj<'static> {}
您正确地识别了您的问题:
In other words &mut some_struct
is lifetime 'a
but needs 'static
您需要将 some_struct
声明为 static
:
fn main() {
static mut SOME_STRUCT: SomeOtherStruct = SomeOtherStruct {};
// ...
let obj = unsafe { Obj::new(&mut SOME_STRUCT) };
// ...
}
问题是,您无法安全地访问可变静态变量,因为它们可以同时突变为多个线程,这是一个问题,因此您需要 unsafe
.
所以不,你的代码不是 "Rust like",但恐怕你不能用你当前的架构改变它。
The trait needs to be 'static because I want to store objects from type Surface
in a Vec<Box<Surface>>
.
我不明白为什么你认为你首先需要 'static
,例如此代码完全合法:
trait Foo {}
struct Bar;
impl Foo for Bar {}
fn main() {
let b: Box<Foo> = Box::new(Bar);
}
有效并解决了我的问题,但感觉很笨拙并且与 Rust 对抗。
根据你的提示,我找到了一个更好的解决方案,它也可以工作并且不使用 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
在 Obj
中存储 Box<SomeOtherStruct>
而不是 &mut SomeOtherStruct
。这将消除生命周期:
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
等
更容易
How to implement a trait with 'static
lifetime for a struct with lifetime 'a
?
你不会也不可能。 'static
生命周期的目的是说 "something that lives for the entire duration of the program"。没有任意生命周期 'a
满足此要求 除了 'static
本身。
我有一个 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>
来解决这个问题,但这会使事情变得更复杂。
要事第一:
impl<'a> Surface for Obj<'a> where 'a: 'static {}
对于
来说是冗长的impl Surface for Obj<'static> {}
您正确地识别了您的问题:
In other words
&mut some_struct
is lifetime'a
but needs'static
您需要将 some_struct
声明为 static
:
fn main() {
static mut SOME_STRUCT: SomeOtherStruct = SomeOtherStruct {};
// ...
let obj = unsafe { Obj::new(&mut SOME_STRUCT) };
// ...
}
问题是,您无法安全地访问可变静态变量,因为它们可以同时突变为多个线程,这是一个问题,因此您需要 unsafe
.
所以不,你的代码不是 "Rust like",但恐怕你不能用你当前的架构改变它。
The trait needs to be 'static because I want to store objects from type
Surface
in aVec<Box<Surface>>
.
我不明白为什么你认为你首先需要 'static
,例如此代码完全合法:
trait Foo {}
struct Bar;
impl Foo for Bar {}
fn main() {
let b: Box<Foo> = Box::new(Bar);
}
根据你的提示,我找到了一个更好的解决方案,它也可以工作并且不使用 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
在 Obj
中存储 Box<SomeOtherStruct>
而不是 &mut SomeOtherStruct
。这将消除生命周期:
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
等
How to implement a trait with
'static
lifetime for a struct with lifetime'a
?
你不会也不可能。 'static
生命周期的目的是说 "something that lives for the entire duration of the program"。没有任意生命周期 'a
满足此要求 除了 'static
本身。