Temporary value dropped while borrowed even when assigning to variable

Getting an error message temporary value dropped while borrowed but I can't figure out why it's being dropped, why is it not being captured by the value variable?

const TEST: OnceCell<String> = OnceCell::new();

let value = TEST.get_or_init(|| {
    "Hello, World!".to_string()

When you name a const, it's almost exactly like you wrote out the const's value in-line. So, your code is equivalent to:

let value = OnceCell::new().get_or_init(|| {
    "Hello, World!".to_string()

This then fails because value is an &String borrowing from the OnceCell, but the OnceCell is a temporary value dropped at the end of the let statement.

You should probably make TEST a static (global variable — has one value, initialized only once) instead of a const. In general, don't use const for values that contain interior mutability or “have an identity” in other ways.

Can't make TEST static, getting error UnsafeCell<Option<String>> cannot be shared between threads safely.

That's because core::cell::OnceCell isn't thread-safe. You need to use the thread-safe version std::sync::OnceLock (recently renamed, and corresponding to once_cell::sync::OnceCell).

1 Like

Any way I can avoid that? I'm in a single threaded environment with no_std

You can structure your program to avoid using global variables (e.g. instead borrowing from things created in main).

Or, if you are really sure that this code will never be run on a system with threads, and that no one will ever try to use it on a system that does, you can write your own wrapper around OnceCell which unsoundly implements Send and Sync.

Prefer the first option. It's a lot safer, and allows you to keep compatibility with all environments. Even if your project's goal is to run on a single-threaded embedded system, it can be useful to be able to run tests against parts of it on the host, and Rust's #[test] mechanism is multithreaded by default. Also, making it possible (even if not mandatory) to use code without it touching any hardcoded global state is good software engineering practice, that makes it easier to adapt the code to future requirements or reuse it in other situations.

So every static and const has to be send/sync?

No, consts don't need to be — as your first program shows — because they're recreated at each place they're used, so merely naming a const can't cause the value to be shared between threads.

Okay, thanks so much for the guidance!!

Since I won't be able to have a static without sync, I'll use the spin library to get a no_std compatible Mutex.

Here's an example

Sorry, left out the example link

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.