gpt4 book ai didi

rust - 如何将拥有的盒装结构引用给其他拥有的结构

转载 作者:行者123 更新时间:2023-11-29 08:00:34 25 4
gpt4 key购买 nike

我有 Engine 拥有 Worker,我希望 Engine 提供一些 API 给 Worker 作为引用去特质。 API 实现是使用 Box 分配的,由 Engine 拥有,因此只要 worker 还活着,对它的引用就是稳定有效的。

但我不明白如何用 Rust 表达它。

我已阅读 Why can't I store a value and a reference to that value in the same struct?我明白为什么我不能传递对拥有值(value)的引用。但是,在我的例子中,我传递的引用不是对自有值本身,而是对不会移动的装箱值,因此对它的引用必须是稳定的。

这是非工作原型(prototype):

trait EngineApi {
fn foo(&self);
}

struct Worker<'a> {
api: &'a EngineApi,
}
impl<'a> Worker<'a> {
fn new(engine_api: &'a EngineApi) -> Self {
Worker { api: engine_api }
}
}

struct Api;
impl EngineApi for Api {
fn foo(&self) {}
}

struct Engine<'a> {
api: Box<Api>,
worker: Box<Worker<'a>>,
}

impl<'a> Engine<'a> {
fn new() -> Self {
let api = Box::new(Api);
let worker = Box::new(Worker::new(api.as_ref()));
Engine { api: api, worker: worker }
}
}

fn main() {
let engine = Engine::new();
}

错误:

test.rs:27:37: 27:40 error: `api` does not live long enough
test.rs:27 let worker = Box::new(Worker::new(api.as_ref()));
^~~
test.rs:25:19: 29:3 note: reference must be valid for the lifetime 'a as defined on the block at 25:18...
test.rs:25 fn new() -> Self {
test.rs:26 let api = Box::new(Api);
test.rs:27 let worker = Box::new(Worker::new(api.as_ref()));
test.rs:28 Engine { api: api, worker: worker }
test.rs:29 }
test.rs:26:27: 29:3 note: ...but borrowed value is only valid for the block suffix following statement 0 at 26:26
test.rs:26 let api = Box::new(Api);
test.rs:27 let worker = Box::new(Worker::new(api.as_ref()));
test.rs:28 Engine { api: api, worker: worker }
test.rs:29 }
error: aborting due to previous error

最佳答案

问题在于,在您的示例中,没有任何东西可以将 api 对象绑定(bind)到比创建它的范围更长的时间。所以基本上您需要先创建整个引擎对象,然后然后 Rust 可以推断这些生命周期。但是如果不填写所有字段,就无法安全地创建对象。但是您可以将 worker 字段更改为 Option 并稍后填写:

struct Engine<'a> {
api: Box<Api>,
worker: Option<Box<Worker<'a>>>,
}

impl<'a> Engine<'a> {
fn new() -> Self {
let api = Box::new(Api);
Engine { api: api, worker: None }
}
fn turn_on(&'a mut self) {
self.worker = Some(Box::new(Worker::new(self.api.as_ref())));
}
}

fn main() {
let mut engine = Engine::new();
engine.turn_on();
}

engine.turn_on() 的调用将锁定对象以确保它留在范围内。那时你甚至不需要盒子来确保安全,因为物体将变得不可移动:

struct Engine<'a> {
api: Api,
worker: Option<Worker<'a>>,
}

impl<'a> Engine<'a> {
fn new() -> Self {
let api = Api;
Engine { api: api, worker: None }
}
fn turn_on(&'a mut self) {
self.worker = Some(Worker::new(&self.api));
}
}

fn main() {
let mut engine = Engine::new();
engine.turn_on();
}

Rust 编译器不能使用对象应该是可移动的事实,因为它引用的东西存储在堆上并且至少与对象一样长。也许在未来的某一天。现在你必须求助于不安全的代码。

关于rust - 如何将拥有的盒装结构引用给其他拥有的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35984589/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com