1

I have a struct that contains a HashMap which is inside a RefCell. I want to implement a method on the struct that essentially is just a layer over the HashMap's get method. Here's a distilled version of the model:

use std::cell::RefCell;
use std::cell::Ref;
use std::ops::Deref;
use std::collections::HashMap;

#[derive(Debug)]
struct Bar {
    content: String
}

struct Foo {
    map: RefCell<HashMap<i32, Bar>>,
}

impl Foo {
    pub fn get_val(&self, key: i32) -> Option<&Bar> {
        self.map.borrow().get(&key)
    }
}

This fails to compile:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:21:9
   |
21 |         self.map.borrow().get(&key)
   |         ^^^^^^^^^^^^^^^^^ temporary value does not live long enough
22 |     }
   |     - temporary value only lives until here
   |

I tried doing something similar to an answer from this similar question:

pub fn get_val(&self, key: i32) -> impl Deref<Target = Option<&Bar>> + '_ {
    Ref::map(self.map.borrow(), |mi| &mi.get(&key))
}

But it doesn't work either:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/main.rs:18:46
   |
18 |         Ref::map(self.map.borrow(), |mi| &mi.get(&key))
   |                                              ^^^
   |

Is it possible to do what I'm trying to do? Or should I rethink my object model?

There is an identical question that was asked in 2015, and the answer suggested putting an Rc inside the HashMap. However, that was before Ref::map was introduced, so I'm hoping there's a better solution in Rust 2018.

Here is a playground link.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Cheezey
  • 700
  • 2
  • 11
  • 29
  • 1
    *so I'm hoping there's a better solution in Rust 2018* There is not. If someone finds one, they should add it to the duplicate — we update Q&A over time to account for language changes. – Shepmaster Sep 01 '18 at 02:32
  • 1
    The difference between `|mi| &mi.vec` (as in the other question) and `|mi| &mi.get(&key)` is that `get` returns an `Option` which is then owned by the closure, so you're not trying to return a reference to the inside of `mi`, you're now trying to return a reference to a local. So that's why it doesn't work. Unfortunately I can't think of a solution, although I think `Ref` could be extended with a `try_map` function to support a fallible `f` argument. – trent Sep 01 '18 at 02:45
  • All right, thanks. Sorry for the duplicate. – Cheezey Sep 01 '18 at 02:56

0 Answers0