简体   繁体   English

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

[英]How to give reference to owned boxed struct to other owned struct

I have Engine which owns Worker and I want Engine to provide some API to Worker as a reference to trait. 我有Engine拥有Worker ,我希望EngineWorker提供一些API作为trait的参考。 API implementation is allocated using Box and is owned by Engine , so reference to it is stable and valid as long as worker is alive. API实现使用Box分配并由Engine拥有,因此只要worker处于活动状态,对它的引用就是稳定且有效的。

But I don't understand how to express it in Rust. 但我不明白如何在Rust中表达它。

I have read Why can't I store a value and a reference to that value in the same struct? 我已经阅读了为什么我不能在同一个结构中存储值和对该值的引用? and I understand why I can't pass reference to owned value. 我理解为什么我不能传递对自有价值的参考。 However, in my case, I pass reference not to owned value itself, but to boxed value, which won't be moved, so reference to it must be stable. 但是,在我的情况下,我将引用传递给不是拥有值本身,而是传递给不会移动的盒装值,因此对它的引用必须是稳定的。

Here is non-working 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();
}

Errors: 错误:

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

The problem is that in your example, there's nothing binding the api object to live longer than the scope it is created in. So basically you'd need to create the entire engine object first, and then Rust could reason about these lifetimes. 问题在于,在您的示例中,没有任何绑定api对象的活动时间比它创建的范围更长。所以基本上你需要先创建整个引擎对象,然后Rust可以推断这些生命周期。 But you can't create an object safely without filling out all fields. 但是,如果不填写所有字段,则无法安全地创建对象。 But you can change the worker field to an Option and fill it out later: 但您可以将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();
}

The call to engine.turn_on() will lock the object to ensure it will stay in the scope. engine.turn_on()的调用将锁定对象以确保它将保留在范围内。 You don't even need boxes to ensure safety then, because the object will become immovable: 你甚至不需要盒子来确保安全,因为物体将变得不可移动:

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();
}

The Rust compiler cannot use the fact that the object should be movable because the things it references are stored on the heap and live at least as long as the object. Rust编译器不能使用对象应该是可移动的这一事实,因为它引用的东西存储在堆上并且至少与对象一样长。 Maybe some day in the future. 也许将来的某一天。 For now you have to resort to unsafe code. 现在你必须求助于不安全的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM