Level: novices, n00bs
Rust is a statically typed language, which helps preventing runtime bugs, and ensures memory safety at compile time, that is with no runtime costs. However, sometimes one may need using dynamic values. Also, Rust doesn't support "out of the box" complex static structures, which still can be solved with some lazy initialization tricks.
Below are some notes on dynamic data types, and global static objects in Rust programming language.
The dynamic crate maintains dynamic data structures using raw memory manipulations via mem::transmute
, and can be used to store a dynamic value. The value still should be casted when dereferencing.
Dependencies:
[dependencies]
dynamic = "0.2"
A basic example:
extern crate dynamic;
use dynamic::Dynamic;
fn main() {
// Create a new Dynamic value.
let x = Dynamic::new(100usize);
// If we try to downcast to the wrong type it will not work.
assert_eq!(x.downcast_ref::<i32>(), None);
// If we downcast to the right type, we get access.
assert_eq!(x.downcast_ref::<usize>(), Some(&100usize));
}
This can further be used to have a vector of dynamic values. For this a convenient dyn_vec!
macro can be introduced:
macro_rules! dyn_vec(
[ $($key:expr),+, ] => {
{
let mut v: Vec<Box<Dynamic>> = Vec::new();
$(
v.push(Dynamic::new($key));
)+
v
}
};
);
Usage:
fn main() {
// Stack of dynamic values.
let mut stack = dyn_vec![
'a',
"string",
20,
];
// 'a' value
println!("stack[0]: {:?}", *stack[0].downcast_ref::<char>().unwrap());
stack.push(Dynamic::new(10.4));
// "string"
println!("stack[1]: {:?}", *stack[1].downcast_ref::<&str>().unwrap());
// 20
println!("stack[2]: {:?}", *stack[2].downcast_ref::<i32>().unwrap());
// 10.4
println!("stack[3]: {:?}", *stack[3].downcast_ref::<f64>().unwrap());
}
The lazy-static crate allows having a complex structure initialized only once, and accessible from other functions.
Dependencies:
[dependencies]
lazy_static = "0.2.8"
Example of a static hash-map (with the convenient hashmap!
macro):
#[macro_use]
extern crate lazy_static;
use std::collections::HashMap;
/**
* A macro for map literals.
*
* hashmap!{ 1 => "one", 2 => "two" };
*/
macro_rules! hashmap(
{ $($key:expr => $value:expr),+, } => {
{
let mut m = ::std::collections::HashMap::new();
$(
m.insert($key, $value);
)+
m
}
};
);
lazy_static! {
static ref STATES_MAP: HashMap<&'static str, Vec<i32>> = hashmap! {
"INITIAL" => vec![1, 2, 3],
"comment" => vec![2, 1, 4],
};
}
fn main() {
let states = STATES_MAP.get("INITIAL").unwrap();
for i in 0..states.len() {
println!("{}", states[i]);
}
}
If we need a mutable static structure, we should use mutex for this:
#[macro_use]
extern crate lazy_static;
// Need to use mutex to use mutable lazy_static!
use std::sync::Mutex;
lazy_static! {
// Since it's mutable and shared, use mutext.
static ref STATES: Mutex<Vec<i32>> = Mutex::new(vec![1, 2, 3]);
}
fn main() {
println!("STATES[0] = {:?}", STATES.lock().unwrap()[0]);
// Push a new element to STATES.
STATES.lock().unwrap().push(4);
println!("STATES[3] = {:?}", STATES.lock().unwrap()[3]);
}