3

I want to store some objects in a Vec and efficiently retrieve them by the value of a field. In practice I want to index it by multiple fields, otherwise I could just use a HashMap. Neither the Vec nor the object fields will be changed later on.

use std::collections::HashMap;

pub struct Data {
    attribute1: i64,
    attribute2: String,
}

pub struct IndexedVector<'a> {
    data: Vec<Data>,
    by_attribute1: HashMap<i64, &'a Data>,
}

impl<'a> IndexedVector<'a> {
    pub fn new() -> Self {
        let mut res = Self {
            data: vec![
                Data {
                    attribute1: 1,
                    attribute2: "foo".into(),
                },
            ],
            by_attribute1: HashMap::new(),
        };
        res.build_index();
        res
    }

    fn build_index(&mut self) {
        for d in &self.data {
            self.by_attribute1.insert(d.attribute1, &d);
        }
    }
}

fn main() {}

It should be possible to do something like this, because the data array lives as as long as the references in the hash map. However, when trying to iterate over the objects in the data array I get the following error

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/main.rs:29:18
   |
29 |         for d in &self.data {
   |                  ^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 28:5...
  --> src/main.rs:28:5
   |
28 | /     fn build_index(&mut self) {
29 | |         for d in &self.data {
30 | |             self.by_attribute1.insert(d.attribute1, &d);
31 | |         }
32 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:29:18
   |
29 |         for d in &self.data {
   |                  ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 13:1...
  --> src/main.rs:13:1
   |
13 | / impl<'a> IndexedVector<'a> {
14 | |     pub fn new() -> Self {
15 | |         let mut res = Self {
16 | |             data: vec![
...  |
32 | |     }
33 | | }
   | |_^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:30:53
   |
30 |             self.by_attribute1.insert(d.attribute1, &d);
   |                                                     ^^
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Antigo
  • 323
  • 3
  • 11
  • This is a variant of "There's one specific case where you can create a type with a reference to itself" in https://stackoverflow.com/q/32300132/155423. The problem is that you can't add values to the `Vec` or even move the value once you've indexed it. Here's [a "solution"](https://play.rust-lang.org/?gist=70d44b2827c750df80c2b943dac320ed&version=stable) that compiles, but is very unlikely to do what you want. – Shepmaster Sep 01 '17 at 14:12

0 Answers0