Analysis of data in a modifiable static variable at module level

I have a set of functions inside a module that need access to some state of initialization time. Effectively, I would like to simulate this with a static mutable vector, for example:

static mut defs: Vec<String> = vec![]; fn initialize() { defs.push("One".to_string()); defs.push("Two".to_string()); } 

(Example: http://is.gd/TyNQVv , fails with "mutable statics are not allowed to have destructors".)

My question is similar to Can global variables be used in Rust? , but uses Vec (i.e. a type with a destructor), so Option seems to not apply to this question. Namely, this happens with the same error as my first attempt:

 static mut defs: Option<Vec<String>> = None; fn initialize() { let init_defs = vec![]; init_defs.push("One".to_string()); init_defs.push("Two".to_string()); defs = Some(init_defs); } 
  • Is there a way to access a static ("global") vector that is populated at initialization time and displayed at runtime?

  • Are there other patterns that I should consider to support this use case? Passing explicit references to the state vector is possible, but it will clutter up a very large number of function signatures that all need access to this state.

+5
source share
1 answer

You can use lazy_static for this purpose:

 lazy_static! { static ref defs: Vec<String> = { let mut init = vec!["One".to_string(), "Two".to_string()]; // init.push(...); etc. etc. init } } 

This initializes the vector on first access, and after that it is unchanged. If you want to change it later, then ending it in std::sync::Mutex is a good first step.

Are there other patterns that I should consider to support this use case? Passing explicit references to the state vector is possible, but it will clutter up a very large number of function signatures that all need access to this state.

One template to consider is the creation of a context object that stores all the information necessary for functions, for example.

 struct Context { defs: Vec<String> } 

and then going around Context ensures that everyone knows what they need to know. You might even consider including all / many / some functions as methods on Context , for example.

 impl Context { fn foo(&self) { if self.defs.len() > 10 { println!("lots of defs"); } } // ... } 

This template is especially good if you need to change the context (automatically ensures thread safety) and / or if you want to have several independent instances in one process.

+9
source

Source: https://habr.com/ru/post/1214531/


All Articles