1

I've been trying to create a simple interpreter in Rust. Here's a code snippet.

use std::vec::Vec;
use std::option::Option;
use std::borrow::Borrow;

trait Data {}

trait Instruction {
    fn run(&self, stack: &mut Vec<Box<Data>>) -> Option<&Data>;
}

struct Get {
    stack_index: usize,
}

impl Instruction for Get {
    fn run(&self, stack: &mut Vec<Box<Data>>) -> Option<&Data> {
        Some(stack[self.stack_index].borrow())
    }
}

fn main() {}

The above contains a simple Get instruction. It has a run method which simply returns a value from the given stack of Data. Data is an abstract trait representing really any type of data. I haven't implemented Data yet.

However compiling the code generates error code E0495

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
  --> <anon>:17:14
   |
17 |         Some(stack[self.stack_index].borrow())
   |              ^^^^^^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 16:63...
  --> <anon>:16:64
   |
16 |       fn run(&self, stack: &mut Vec<Box<Data>>) -> Option<&Data> {
   |  ________________________________________________________________^ starting here...
17 | |         Some(stack[self.stack_index].borrow())
18 | |     }
   | |_____^ ...ending here
note: ...so that reference does not outlive borrowed content
  --> <anon>:17:14
   |
17 |         Some(stack[self.stack_index].borrow())
   |              ^^^^^
note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the body at 16:63...
  --> <anon>:16:64
   |
16 |       fn run(&self, stack: &mut Vec<Box<Data>>) -> Option<&Data> {
   |  ________________________________________________________________^ starting here...
17 | |         Some(stack[self.stack_index].borrow())
18 | |     }
   | |_____^ ...ending here
note: ...so that expression is assignable (expected std::option::Option<&Data>, found std::option::Option<&Data>)
  --> <anon>:17:9
   |
17 |         Some(stack[self.stack_index].borrow())
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

What am I missing?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Abogical
  • 13
  • 3

1 Answers1

3

As explained in What is the return type of the indexing operation on a slice?, stack[self.stack_index] is returning the value in the slice by value. You are then trying to return a reference to the local variable, which is disallowed as explained in Is there any way to return a reference to a variable created in a function?.

Really, you would want to do Some(&*stack[self.stack_index]), which dereferences the Box to get to a Data and then re-references it. Because your implementation doesn't fit the rules for lifetime elision, you need to add explicit lifetimes to your trait method and the implementation:

fn run<'a>(&self, stack: &'a mut Vec<Box<Data>>) -> Option<&'a Data>

I'd probably implement it using get and map though:

stack.get(self.stack_index).map(Box::as_ref)
Community
  • 1
  • 1
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Thanks for answering! But If I understand correctly, [this doesn't work :/](https://play.rust-lang.org/?gist=2dc89d594443628eb548d5e75e1fcfc3&version=stable&backtrace=0) – Abogical Apr 17 '17 at 18:21
  • @Abogical you'll need to [change the trait definition and the implementation](https://play.integer32.com/?gist=d619b6bbc9a32a0755cc4aa7f80cdbe3&version=stable); I've clarified that point in the answer. – Shepmaster Apr 17 '17 at 18:24
  • Oh yes, sorry for the dumb mistake, Thank you! – Abogical Apr 17 '17 at 18:35