关于Rust生存期的问题

时间:2017-04-05 06:32:27

标签: rust lifetime

我正在尝试基于TypedArena实现内存池。这是我原始代码的简化版本:

#![feature(rustc_private)]
extern crate arena;
use arena::TypedArena;

pub struct MemoryPool {
    arena: TypedArena<Vec<u8>>,
    bytes_allocated: usize,
}

impl MemoryPool {
    pub fn consume(&mut self, buf: Vec<u8>) -> &[u8] {
        self.bytes_allocated += buf.capacity();
        self.arena.alloc(buf)
    }
}

pub struct ByteArray<'a> {
    data: &'a [u8],
}

impl<'a> ByteArray<'a> {
    pub fn set_data(&mut self, data: &'a [u8]) {
        self.data = data;
    }
}

pub struct S<'a> {
    pool: &'a mut MemoryPool,
}

impl<'a> S<'a> {
    pub fn write(&mut self, buffer: &mut ByteArray<'a>) {
        let v = vec!();
        let data = self.pool.consume(v);
        buffer.set_data(data);
    }
}

然而,编译器抱怨该行:let data = self.pool.consume(v);

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> <anon>:34:26
   |
34 |     let data = self.pool.consume(v);
   |                          ^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 32:54...
  --> <anon>:32:55
   |
32 |     pub fn write(&mut self, buffer: &mut ByteArray<'a>) {
   |  _______________________________________________________^ starting here...
33 | |     let v = vec!();
34 | |     let data = self.pool.consume(v);
35 | |     buffer.set_data(data);
36 | |   }
   | |___^ ...ending here
note: ...so that reference does not outlive borrowed content
  --> <anon>:34:16
   |
34 |     let data = self.pool.consume(v);
   |                ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the body at 32:54...
  --> <anon>:32:55
   |
32 |     pub fn write(&mut self, buffer: &mut ByteArray<'a>) {
   |  _______________________________________________________^ starting here...
33 | |     let v = vec!();
34 | |     let data = self.pool.consume(v);
35 | |     buffer.set_data(data);
36 | |   }
   | |___^ ...ending here
note: ...so that types are compatible (expected &mut ByteArray<'_>, found &mut ByteArray<'a>)
  --> <anon>:35:12
   |
35 |     buffer.set_data(data);
   |            ^^^^^^^^

我的问题是:

  1. 为什么data没有生命周期'a ?我认为,由于pool的有效期为aconsume的有效期与self相同,因此它的有效期为'a

    < / LI>
  2. 使此代码按预期工作的最佳方法是什么?基本上我想分配新字节并将其生命周期调整为与内存池相同。我知道我可以直接使用TypedArena,因为alloc没有mut引用。但是,我真的想跟踪其他信息,例如bytes_allocated

1 个答案:

答案 0 :(得分:0)

让我们一步一步解决这个问题:

cannot infer an appropriate lifetime for autoref

“autoref”描述了为方法的self参数构建正确引用的过程。编译器无法找到具有正确生命周期的引用来调用consume()。为什么不能?

note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 32:54...
  --> <anon>:32:55
   |
32 |     pub fn write(&mut self, buffer: &mut ByteArray<'a>) {
   |  _______________________________________________________^ starting here...
33 | |     let v = vec!();
34 | |     let data = self.pool.consume(v);
35 | |     buffer.set_data(data);
36 | |   }
   | |___^ ...ending here
note: ...so that reference does not outlive borrowed content
  --> <anon>:34:16
   |
34 |     let data = self.pool.consume(v);
   |                ^^^^^^^^^

“匿名生命#1”是指&mut self的生命周期。这句话只是说:我们无法将生命周期超过self生命周期的引用传递给consume():那么consume()会认为它的self参数存在比它实际上更长。

note: but, the lifetime must be valid for the lifetime 'a

这是您预期应用的规则。但问题现在在哪里?好吧:&mut self(匿名生命#1)的生命周期更短而不是'a!就这样!我们可以很容易地解决它:

impl<'a> S<'a> {
    pub fn write<'b: 'a>(&'b mut self, buffer: &mut ByteArray<'a>) {
        //      ^^^^^^^^  ^^
        ...
    }
}

在这里,我们只是命名以前的匿名生命#1,以便能够绑定它,并说它必须寿命 'a(活得比'a长。)< / p>