1

In my Rust project, I need a globally hold, static array or vec that is initialized once where modules can register values or functions on. I thought, this would be possible using the lazy_static!-crate, but it doesn't seem so.

This is what I want to achieve:

  • Module a initializes an array/vec with some data.
  • Module b (or further modules) then extend this array/vec to further data.
  • All this should only be done once at program startup, and the array won't be modified during the program's execution. It is just a lookup-table, globally hold, but once created from several modules.

This is my first draft, which does not work playground link

mod a
{
    use lazy_static::lazy_static; // 1.4.0

    lazy_static!{
        #[derive(Debug)]
        pub static ref TEST: Vec<u32> = vec![1, 2, 3];
    }
}

mod b  // when module b is removed, it works. 
{
    use lazy_static::lazy_static; // 1.4.0
    use crate::a::TEST;

    lazy_static!{
        TEST.extend(vec![4, 5, 6]);
    }
}

use a::TEST;

fn main() {
    for i in 0..TEST.len() {
        println!("{}", TEST[i]);
    }
}

Can anybody help?

1

1 Answer 1

3

A couple things to note:

  • as far as I know, lazy_static! is for declaring static variables, so mod b can't use the macro just to mutate other statics, like you are trying in your example
  • for statics to be mutable in Rust, you need to wrap them in a Mutex to follow Rust's whole thing of guaranteeing thread safety
  • modules are designed to collect things like structs, functions, traits, etc., so if you want them to 'do' something, you need to have it in a function call.

All that being said, I hope this snippet can help you out.

Rust Playground

mod a {
    use lazy_static::lazy_static; // 1.4.0
    use std::sync::Mutex;

    lazy_static!{
        #[derive(Debug)]
        pub static ref TEST: Mutex<Vec<u32>> = Mutex::new(vec![1, 2, 3]);
    }
}

mod b {
    use crate::a::TEST;
    
    pub fn append_to_test() {
        TEST.lock().unwrap().extend(vec![4, 5, 6]);
    }
}

use a::TEST;

fn main() {
    crate::b::append_to_test();
    
    println!("{:?}", TEST.lock().unwrap());
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you, this is exactly the solution I was looking for! You're right, I read about mutexes some time ago but didn't remember about it in detail.
Is there any way to call crate::b::append_to_test() automatically BEFORE the main() or any tests of the crate are being executed? Here's another playground for this case (renamed some functions): play.rust-lang.org/…
Technically no, you cannot execute code before main(), as that is the entry point to the program. If you just want it to be logically separated, however, you can use a SyncLazy if you are running Rust Nightly. This is definitely not the most elegant way of writing it, as I've just shoehorned some code into your example, but this playground creates a global static SyncLazy which wraps a::ITEMS, as well as calls the methods.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.