Methods on static muts

Is there a way to call methods on static muts? The only workarounds i have found are to either use functions instead of methods or raw pointers.

struct A {
    // Holds value that are expensive  to clone
    val: u64,
}

impl A {
    fn get_ref(&self) -> u64 {
        self.val
    }
    fn get_own(self) -> u64 {
        self.val
    }
    fn get_mut(&mut self) -> u64 {
        self.val
    }
}

static mut HOLD: A = A {val: 0};

fn main() {
    unsafe {
        // Cant create a refernce to static mut
        let a = HOLD.get_ref();
        let b = HOLD.get_mut();
        // Cant move out of static mut
        let c = HOLD.get_own();
        // Onyl workaround (Gets marked by clippy)
        let d = (*(&raw const HOLD)).get_ref();
        let e = (*(&raw mut HOLD)).get_ref();
    }
}

fn b() -> u64 {
    unsafe {
        HOLD.val
    }
}

static mut is extremely difficult to use soundly. Outside of some very narrow use cases, you should instead by using a static (without mut) and a type that provides sound interior mutability, such as Mutex or AtomicU64.

use std::sync::atomic;

struct A {
    val: atomic::AtomicU64,
}

impl A {
    fn get(&self) -> u64 {
        self.val.load(atomic::Ordering::Relaxed)
    }
}

static HOLD: A = A {val: atomic::AtomicU64::new(0)};

fn main() {
    let val = HOLD.get();
}

If you can’t express what you need using an existing type, then you can write your own interior-mutable type (with &self methods!) that uses UnsafeCell internally. Such code needs to be reviewed carefully for soundness.

2 Likes

Stop using static mut and everything will go better. Make it just static HOLD: A instead, and have the appropriate things inside the A (such as a Mutex<u64>) or whatever.

Or just have it be static HOLD: Mutex<A> in the first place.

1 Like

error[E0507]: cannot move out of static item HOLD
--> src/main.rs:16:11
|
16 | let val = HOLD.get();
| ^^^^ move occurs because HOLD has type A, which does not implement the Copy trait

Oops, I made a typo in my post. The fn get(self) should be fn get(&self).

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.