Search code examples
rustreadwritelocklazy-static

Return a reference to a T inside a lazy static RwLock<Option<T>>?


I have a lazy static struct that I want to be able to set to some random value in the beginning of the execution of the program, and then get later. This little silly snippet can be used as an example:

use lazy_static::lazy_static;
use std::sync::RwLock;

struct Answer(i8);

lazy_static! {
    static ref ANSWER: RwLock<Option<Answer>> = RwLock::new(None);
}

fn answer_question() {
    *ANSWER.write().unwrap() = Some(Answer(42));
}

fn what_is_the_answer() -> &'static Answer {
    ANSWER
        .read()
        .unwrap()
        .as_ref()
        .unwrap()
}

This code fails to compile:

error[E0515]: cannot return value referencing temporary value
  --> src/lib.rs:15:5
   |
15 |        ANSWER
   |   _____^
   |  |_____|
   | ||
16 | ||         .read()
17 | ||         .unwrap()
   | ||_________________- temporary value created here
18 | |          .as_ref()
19 | |          .unwrap()
   | |__________________^ returns a value referencing data owned by the current function

I know you can not return a reference to a temporary value. But I want to return a reference to ANSWER which is static - the very opposite of temporary! I guess it is the RwLockReadGuard that the first call to unwrap returns that is the problem?

I can get the code to compile by changing the return type:

fn what_is_the_answer() -> RwLockReadGuard<'static, Option<Answer>> {
    ANSWER
        .read()
        .unwrap()
}

But now the calling code becomes very unergonomic - I have to do two extra calls to get to the actual value:

what_is_the_answer().as_ref().unwrap()

Can I somehow return a reference to the static ANSWER from this function? Can I get it to return a RwLockReadGuard<&Answer> maybe by mapping somehow?


Solution

  • once_cell is designed for this: use .set(...).unwrap() in answer_question and .get().unwrap() in what_is_the_answer.