如何使用'具有生命周期的结构的静态生命周期'来实现特征?

问题描述 投票:2回答:3

我有一个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解决这个问题,但这会使事情变得更复杂。

rust traits lifetime
3个回答
2
投票

如何使用Rc<T>生命周期为具有生命周期'static的结构实现特征?

你不能也不能。 'a一生的目的是说“在整个计划期间生活的东西”。除'static本身外,没有任意生命'a符合此要求。


3
投票

首先要做的事情:

'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

1
投票

trait Foo {} struct Bar; impl Foo for Bar {} fn main() { let b: Box<Foo> = Box::new(Bar); } 工作并解决了我的问题,但它感觉hacky和反对Rust。

有了你的提示,我找到了一个更好的解决方案,alsos工作,不使用@hellow's answer

解决方案1

我为unsafeManager类型指定了显式生命周期参数:

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),更容易避免生命和使用Objtrait 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); } 等。

© www.soinside.com 2019 - 2024. All rights reserved.