如何将拥有的盒装结构引用给其他拥有的结构
How to give reference to owned boxed struct to other owned struct
我有 Engine
,它拥有 Worker
,我希望 Engine
向 Worker
提供一些 API 作为特征的参考。 API 实现是使用 Box
分配的,并由 Engine
拥有,因此只要 worker 还活着,对它的引用就是稳定有效的。
但是我不明白用Rust怎么表达。
我已阅读 并且我明白为什么我不能传递对自有值的引用。但是,在我的例子中,我传递的引用不是拥有的值本身,而是盒装值,它不会被移动,所以对它的引用必须是稳定的。
这是非工作原型:
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
对象绑定到比创建它的范围更长的时间。所以基本上您需要先创建整个引擎对象,然后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 编译器不能使用对象应该是可移动的事实,因为它引用的东西存储在堆上并且至少与对象一样长。也许在未来的某一天。现在你必须求助于不安全的代码。
我有 Engine
,它拥有 Worker
,我希望 Engine
向 Worker
提供一些 API 作为特征的参考。 API 实现是使用 Box
分配的,并由 Engine
拥有,因此只要 worker 还活着,对它的引用就是稳定有效的。
但是我不明白用Rust怎么表达。
我已阅读
这是非工作原型:
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
对象绑定到比创建它的范围更长的时间。所以基本上您需要先创建整个引擎对象,然后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 编译器不能使用对象应该是可移动的事实,因为它引用的东西存储在堆上并且至少与对象一样长。也许在未来的某一天。现在你必须求助于不安全的代码。