How can I use mutable lazy_static?

I use a large stack for my program, so I tried to use lazy_static.

#[macro_use]
extern crate lazy_static;

lazy_static! {
    static ref VEC: Vec<i32> = {
        let mut m = Vec::with_capacity(1000);
        m
    };
}

fn main() {
    VEC.push(3);
}

The compiler complains "cannot borrow immutable borrowed content as mutable".
I tried to insert "mut" in declaration part of VEC and failed.

How can I use mutable lazy_static?

6 Likes

You need a Mutex (https://doc.rust-lang.org/nightly/std/sync/struct.Mutex.html).

5 Likes

Thanks for your hint, I found the following code in Stackoverflow.

#[macro_use]
extern crate lazy_static;

use std::sync::Mutex;

lazy_static! {
    static ref ARRAY: Mutex<Vec<u8>> = Mutex::new(vec![]);
}

fn do_a_call() {
    ARRAY.lock().unwrap().push(1);
}

fn main() {
    do_a_call();
    do_a_call();
    do_a_call();

    println!("called {}", ARRAY.lock().unwrap().len());
}

Thank you!

6 Likes

I am facing a similar situation but do not have access to locks or Mutexes and the code I am working on is guaranteed to be single threaded.
How do I create a mutable global hash map?

2 Likes

"guaranteed to be single threaded" is something that you are asserting, but which the compiler has no way to prove. In this kind of cases, you need to use unsafe code.

static mut used to be the standard answer to this kind of problems, but it was recently realized that it is almost impossible to use correctly in Rust (because aliasing of &mut is UB), to the point where the lang team seriously considers deprecating it nowadays.

What you want instead is likely a newtype of UnsafeCell, that implements Sync so that you can use it in a static. There have been discussions of providing such a newtype in the standard library as part of the static mut deprecation process (it would be called RaceyCell or similar), but that hasn't been done yet so you need to roll your own.

1 Like

You can wrap your type with Arc<Mutex<YourType>> and you will have a mutable access to the inner type and thread safe as well.

OP said that Mutexes are not allowed (I guess the code is no_std or something)

Oops, missed to see it. Then in that case lazy_static can't help. You can use Rc<RefCell<YourType>> instead and pass them around, since it can not be instantiated using lazy_static, since lazy_static requires thread safety.

Thanks a lot @HadrienG and @ivanceras for the detailed replies.
Rc<RefCell<>> solves the problem. I will wait for RaceyCell.

2 Likes