首页 文章

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

提问于
浏览
2

我有 Engine 拥有 Worker ,我希望 EngineWorker 提供一些API作为特征的引用 . API实现使用 Box 分配,并由 Engine 拥有,因此只要worker处于活动状态,对它的引用就是稳定且有效的 .

但我不明白如何在Rust中表达它 .

我已经阅读了Why can't I store a value and a reference to that value in the same struct?,我理解为什么我可以移动,所以对它的引用必须是稳定的 .

这是非工作原型:

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

1 回答

  • 2

    问题在于,在您的示例中,没有任何内容绑定 api 对象的活动时间比它创建的范围更长 . 所以基本上你'd need to create the entire engine object first, and then Rust could reason about these lifetimes. But you can' t安全地创建一个对象而不填写所有字段 . 但您可以将 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编译器不能使用对象应该是可移动的这一事实,因为它引用的东西存储在堆上并且至少与对象一样长 . 也许将来的某一天 . 现在你必须求助于不安全的代码 .

相关问题