我如何获得持久的`Vec 。last()`指针?

问题描述 投票:0回答:1

我正在尝试在Rust中构建虚拟机,并且遇到了(我认为是)基本的生存期问题。

以下是VM的相关部分:

#[derive(Copy, Clone)]
enum Value<'v> {
    Bool(bool),
    Str(&'v str),
    Empty,
}

// Updated VM
struct VM<'vm> {
    values: Vec<Value<'vm>>,

    // `VM.strings` will keep references to "result" strings, like those from `concat`.
    strings: Vec<String>,
}

impl<'vm> VM<'vm> {
    // Pushes the given value onto the stack.
    // Returns the index of the value.
    fn push_value(&mut self, value: Value<'vm>) -> usize {
        self.values.push(value);
        return self.values.len() - 1;
    }

    fn get_value(&self, index: usize) -> Value<'vm> {
        // Assume the best of our users...
        return unsafe { *self.values.get_unchecked(index) };
    }

    fn concat(&mut self, i1: usize, i2: usize) -> usize {
        let first = self.get_value(i1);
        let second = self.get_value(i2);
        let result = match (first, second) {
            (Value::Str(v1), Value::Str(v2)) => [v1, v2].concat(),
            _ => panic!("Attempted to CONCAT non-strings."),
        };

        self.strings.push(result);
        let result_ptr = self.strings.last().unwrap();
        self.push_value(Value::Str(result_ptr))
    }
}

我正在尝试为两个字符串编写concat操作。这是我的尝试:

Rust编译器给了我我不完全理解的详细错误:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
  --> src/lib.rs:38:39
   |
38 |         let result_ptr = self.strings.last().unwrap();
   |                                       ^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 29:5...
  --> src/lib.rs:29:5
   |
29 | /     fn concat(&mut self, i1: usize, i2: usize) -> usize {
30 | |         let first = self.get_value(i1);
31 | |         let second = self.get_value(i2);
32 | |         let result = match (first, second) {
...  |
39 | |         self.push_value(Value::Str(result_ptr))
40 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/lib.rs:38:26
   |
38 |         let result_ptr = self.strings.last().unwrap();
   |                          ^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'vm` as defined on the impl at 16:6...
  --> src/lib.rs:16:6
   |
16 | impl<'vm> VM<'vm> {
   |      ^^^
note: ...so that the types are compatible
  --> src/lib.rs:39:14
   |
39 |         self.push_value(Value::Str(result_ptr))
   |              ^^^^^^^^^^
   = note: expected  `&mut VM<'_>`
              found  `&mut VM<'vm>`

一些杂念:

  • 错误似乎与last()指针的生存期有关。我想我理解这一点:因为可以从Vec中删除元素,所以last()指针仅在短时间内有效(在您的函数内)。我知道我不会从VM.strings中删除元素:有没有办法告诉编译器呢?
  • 我曾考虑将枚举变量更改为Str(String),但随后Value将不再是Copy,我认为这是寄存器值的重要特征。另外,因为我不会更改String值,所以感觉&str在这里更“正确”吗?
rust lifetime
1个回答
0
投票

这里是concat函数的修改版本,其中包含对所做更改的注释:

impl<'vm> VM<'vm> {
  // &mut self changed to &'vm mut self
  // this is where the "anonymous lifetime" error happened
  fn concat(&'vm mut self, i1: usize, i2: usize) -> usize {
    let first = self.get_value(i1);
    let second = self.get_value(i2);
    let result = match (first, second) {
      (Value::Str(v1), Value::Str(v2)) => [v1, v2].concat(),
      _ => panic!("Attempted to CONCAT non-strings."),
    };

    self.strings.push(result);
    let result_ptr = self.strings.last().unwrap();
    // can't use self.push_value here since borrow errors
    self.values.push(Value::Str(result_ptr));
    self.values.len() - 1
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.