2

I have code like this:

#[macro_use]
extern crate lazy_static;

use std::collections::HashMap;
use std::cell::RefCell;
use std::sync::{RwLock, RwLockReadGuard, LockResult};

lazy_static! {
    static ref SUBS: RwLock<HashMap<String, String>> = RwLock::new(HashMap::new());
}

pub fn get_sub(key: &str) -> Option<&String> {
    let subs: LockResult<RwLockReadGuard<HashMap<String, String>>> = SUBS.read();
    let x: RwLockReadGuard<HashMap<String, String>> = subs.unwrap();
    x.get(key)
}

And it doesn't compile:

error: `x` does not live long enough
  --> src/main.rs:15:5
   |
15 |     x.get(key)
   |     ^ does not live long enough
16 | }
   | - borrowed value only lives until here
   |
note: borrowed value must be valid for the anonymous lifetime #1 defined on the body at 12:45...
  --> src/main.rs:12:46
   |
12 |   pub fn get_sub(key: &str) -> Option<&String> {
   |  ______________________________________________^ starting here...
13 | |     let subs: LockResult<RwLockReadGuard<HashMap<String, String>>> = SUBS.read();
14 | |     let x: RwLockReadGuard<HashMap<String, String>> = subs.unwrap();
15 | |     x.get(key)
16 | | }
   | |_^ ...ending here

I am completely stumped. I don't understand why this doesn't compile.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
RokL
  • 2,663
  • 3
  • 22
  • 26

1 Answers1

2

You're returning a reference to object inside the hash table, which can be altered/removed by others at any time.

The easiest way is to clone it:

pub fn get_sub(key: &str) -> Option<String> {
    //                              ^~~~~~ change the signature
    let subs: LockResult<RwLockReadGuard<HashMap<String, String>>> = SUBS.read();
    let x: RwLockReadGuard<HashMap<String, String>> = subs.unwrap();
    x.get(key).cloned()
    //         ^~~~~~ Option::cloned()
}

In the case that you wanted a completely constant (immutable) lookup table, check out the phf crate.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Tatsuyuki Ishi
  • 3,883
  • 3
  • 29
  • 41