I cannot set value for OnceCell

I have tried both std::cell::oncecell and smol::lock::OnceCell. Same result.

First, I have pub const INGRESS_KIND: OnceCell<GroupVersionKind> = OnceCell::new(); in a module a. GroupVersionKind is a struct with three String members.

Then in main.rs, in async main function, I have this at the beginning.

let y = GroupVersionKind {
        group: "networking.k8s.io".to_owned(),
        version: "v1".to_owned(),
        kind: "Ingress".to_owned(),
    };
    match INGRESS_KIND.set(y).await {
        Ok(_) => tracing::debug!("{:?}", INGRESS_KIND.get().unwrap()),
        Err(_) => panic!("Cannot init INGRESS_KIND"),
    }

The set always returns Ok, std version or smol version. But INGRESS_KIND.get() always returns None.

What did I do wrong?

use a static and not a const

1 Like

Because you’re using a const for your INGRESS_KIND.
The value of a const is basically copied everywhere you use it. Thus your INGRESS_KIND.set(y) always operates on a new value.
See also the const docs.

Change it to pub static INGRESS_KIND and it will work.

1 Like

using const for global variables is a common mistake of new learners. you need static instead.

const in rust literally means constant, it does NOT mean immutable/readonly global. a const is more like #define in C/C++, meaning the compiler just substitutes its value when you use it.

in other words, given INGRESS_KIND is a const of value OnceCell::new(), when you write INGRESS_KIND.set(y), it's literally equivalent to OnceCell::new().set(y).

1 Like

I recommend using clippy. It is a very helpful tool for avoiding common mistakes, especially for beginners. For a reduced version of your code it gives me

use std::cell::OnceCell;

pub struct GroupVersionKind {}
pub const INGRESS_KIND: OnceCell<GroupVersionKind> = OnceCell::new(); 

pub fn main() {
    let _ = INGRESS_KIND.set(GroupVersionKind{});
}
warning: named constant with interior mutability
 --> src/main.rs:4:11
  |
4 | pub const INGRESS_KIND: OnceCell<GroupVersionKind> = OnceCell::new(); 
  |           ^^^^^^^^^^^^
  |
  = help: did you mean to make this a `thread_local!` item
  = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.91.0/index.html#declare_interior_mutable_const
  = note: `#[warn(clippy::declare_interior_mutable_const)]` on by default

warning: borrow of a named constant with interior mutability
 --> src/main.rs:7:13
  |
7 |     let _ = INGRESS_KIND.set(GroupVersionKind{});
  |             ^^^^^^^^^^^^
  |
  = note: there is a compiler inserted borrow here
  = help: this lint can be silenced by assigning the value to a local variable before borrowing
  = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.91.0/index.html#borrow_interior_mutable_const
  = note: `#[warn(clippy::borrow_interior_mutable_const)]` on by default
2 Likes

Right, I should have it enabled in analyzer. Thanks.