0

I have a symbol table that I want to be static because it is accessed in a lot of circumstances where I don't have a good way to pass the value in. It is a struct and a table that looks like:

struct Symbol {
   string: &'static str,
   other_values: ...,
}
const NO_SYMBOL = Symbol{ string: "", other...};
static mut symbol_table : [Symbol;100] = [NO_SYMBOL;100];

How do I update the string field? It has to be static, because it's in a static array, but I want to generate values (among other things, by reading from a file), so how can I make a String static so I can store it in an element of the array?

5
  • 1
    &'static str is a string either baked in the binary or leaked. Are you sure you really need this and not String/Box<str>? Commented Mar 26, 2021 at 4:21
  • Alternatively, a Cow<'static, str> would allos mixing static strings created at compile time and dynamic strings allocated at runtime. Commented Mar 26, 2021 at 6:34
  • 2
    Either way using lazy_static! with proper synchronisation would probably be a better idea than a bare static mut`, those are gnarly. Commented Mar 26, 2021 at 6:35
  • Do you need to update the strings only once or multiple times? Commented Mar 26, 2021 at 10:55
  • I am OK with leaking the strings. I only need to update each string once, but new ones will be slowly added over the life of the program (which could be days), and once added they will very rarely stop being used (and I can manually discard them in those rare cases). I don't need Cow, I don't think. I'd be perfectly fine with having copies of the strings as there will be very few baked in the binary. String or Box<str> sounds OK, but how can I initialize it? I could use unsafe uninitialized data, as I could initialize values before I access them, but I'd prefer to keep it cleaner. Commented Mar 26, 2021 at 12:42

1 Answer 1

1

There are a couple of ways to do this, depending on what you think is best. Use a Vec:

static mut symbol_table_1:Vec<Symbol> = Vec:new(); //doesn't actually allocate so is a const fn

or use an option and replace the none values:

static mut symbol_table_2:[Option<Symbol>;100] = [None;100];

unsafe{
    symbol_table_2[0].replace(Some(value));
}

A &'static str can be obtained by using String::into_boxed_str and Box::leak. However, I would highly encourage you to use lazy_static and an RwLock, which enables many readers or one writer to maintain a lock on the static and prevent data races.

lazy_static!{
    static ref symbol_table_3:Rwlock<Vec<Symbol>> = RwLock::new(Vec::new());
}

Full playground link

Sign up to request clarification or add additional context in comments.

4 Comments

Box::leak(s.into_boxed_str()) works great, and I was leaning toward a Vec and RwLock, so I've done that. My question now is in the rare cases where I actually am deleting one of the strings, I could recover that space if I could turn the &'static str back into a String that I could then drop. As I've said, not a huge deal if it's impossible, but it would be nice and clean.
@DaveMason you can recover the memory by using the box::from_raw method, but be very sure that the str is not in use anywhere if you do that.
Thanks @Aiden4 - is that safe regardless of whether the original str came from a String or Cow or literal? Ahh... I'm guessing the into_boxed_str makes it something that can be safely brought back with from_raw.
@DaveMason Don't deallocate a string literal that way- only deallocate &str's that are not in use anywhere and were heap-allocated either in a box or a string or similar. The Cow should be fine if you do to_owned and leak the resulting string.

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.