I need to use a string for the entire life of the program. But the string is actually computed at runtime (actually by a separate process, so I get it using std::process::Command). Here's the idea (which doesn't work):
#[macro_use] extern crate lazy_static;
fn main() {
let a = expensive_to_compute_data();
println!("{}", a);
let b = expensive_to_compute_data();
println!("{}", b);
}
lazy_static! {
pub static ref DATA: String = String::new();
}
pub fn expensive_to_compute_data() -> &'static str {
if DATA.is_empty() { // Will only happen once
let s = "VERY EXPENSIVE COMPUTATION";
DATA.push_str(s);
}
&DATA
}
Is this doable? If so, how? Playground
This seems to work though:
fn main() {
let a = expensive_to_compute_data();
println!("{}", a);
let b = expensive_to_compute_data();
println!("{}", b);
}
static mut DATA: &str = "";
pub fn expensive_to_compute_data() -> &'static str {
unsafe {
if DATA.is_empty() {
DATA = get_data();
}
DATA
}
}
pub fn get_data() -> &'static str {
"VERY EXPENSIVE COMPUTATION"
}
#[macro_use]
extern crate lazy_static;
use std::sync::Mutex;
lazy_static! {
static ref DATA: Mutex<Vec<u8>> = Mutex::new(vec![]);
}
fn main() {
expensive_initialize_data() ;
let a = get_data();
println!("{}", a);
let b = get_data();
println!("{}", b);
}
pub fn expensive_initialize_data() {
let mut b = vec![65, 66, 67, 97, 98, 99];
DATA.lock().unwrap().append(&mut b);
}
pub fn get_data() -> String {
String::from_utf8(DATA.lock().unwrap().to_vec()).unwrap()
}
The downside is the mutex & conversion cost at each get_data() call; but this is nothing compared to the expense of initializing, so doesn't matter to me.
I must be missing an important aspect of your problem, but why couldn't some variation of this work ?
lazy_static! {
pub static ref DATA: String = expensive_to_compute_data();
}
pub fn expensive_to_compute_data() -> String {
// Will only happen once
let s = String::from("VERY EXPENSIVE COMPUTATION");
s
}
@HadrienG you didn't miss a thing! That's exactly what I needed. I had forgotten that the function would only be called the first time it was needed, i.e., at runtime.
use lazy_static::lazy_static;
lazy_static! {
pub static ref DATA: String = expensive_to_compute_data();
}
fn expensive_to_compute_data() -> String {
// Will only happen once
let s = String::from("VERY EXPENSIVE COMPUTATION");
s
}
fn get_str_ref() -> &'static str {
&DATA
}
fn main() {
println!("{}", get_str_ref());
}
However, it doesn't work if I directly put a &DATA in the println statement, because the implicit coercion to &str is not performed in that case. Maybe that's what you observed?