How static lifetime works?

fn main() {
    let mut x = 1234;
    ok(&mut x);
    println!("{}", x);
}

pub fn ok<'s>(_z: &'static mut i32) {}

(Playground)

Questions:

  1. after execution of ok its release the local z variable so it means x is not borrowed. But why does the second error shows x cant borrow immutable because it also borrowed as mutable

According to the signature, it doesn't.

What is the mean of the signature

  1. Function borrows a value that has a static lifetime
    Or
  2. Anything else..

Yes, 1. The static lifetime gives the ok function permission to keep the mutable borrow after it returns (even if the current implementation does nothing).

1 Like

In particular, it could do something like this, since 'static references can be stored in globals. This generally isn't a problem, since most ways of getting 'static references either prevent use of the original value, or keep the reference only temporarily, or only use shared references (which are Copy), which avoid this problem in different ways. The code in the original post is a case where 'static shouldn't be used anyway, since x can't live for the static lifetime.

2 Likes

When verifying lifetimes in the main function, the Rust compiler does not actually look inside ok. Instead, it looks only at the signature of ok, and it verifies that main would be correct no matter what happens inside ok as long as ok follows its own signature.

That means that if main compiles, then main will still compile if you change the body of ok without changing the signature. There are various bad things that ok could do with its signature, such as the example that @jameseb7 posted, and since the signature of ok allows those, main does not compile.

7 Likes
static mut HOLDER: i32 = 44;

fn main() {
    unsafe {
        ok(&mut HOLDER);
        println!("{}", HOLDER);
    }
}

pub fn ok(z: &'static mut i32) {}
  1. but why this works?

Well a global variable can indeed exist forever.

In the first main question

  1. x still borrowed not compiled.
  2. But the above question compiled

Why..what is the difference between both of them.

The difference is that the problem you ran into in the original code is not checked when you use a static mut. This is one of the reasons that static mut requires an unsafe block.

2 Likes

Can you pls explain it

When you perform an operation that requires an unsafe block, then there are various rules that you must follow, but the compiler cannot check them. If you break the rules, then all sorts of bad stuff can happen.

I'd like to note that println isn't the only problem in your original code. Even if you remove println, the code won't compile because you don't actually have a &'static mut i32. You can't get a static reference to a local variable on the stack because the compiler can't guarantee that it will be available forever.

You could allocate the value on the heap and use Box::leak to get a static reference to it:

fn main() {
    let x = Box::leak(Box::new(1234));
    ok(x);
}

This will work, but only once: after you pass x to ok, you won't be able to use x anymore from the outside.

Your example with static mut works because when you do println!("{}", HOLDER), you create a new reference to the static variable instead of using the same reference that you passed to ok. When you do this, you have to manually make sure you're not aliasing mutable references, so it only works inside the unsafe block.

1 Like

'static lifetime means "this memory is never freed". It describes either memory compiled into the program itself (a constant number, literal string) or leaked memory. Because constants are only predefined at compile time, and leaking memory is problematic, &'static references in Rust are very very rarely usable. 'static is a rare exception, almost all references in Rust are not static.

There is also a common idiom in generic code: T: 'static. It does not make it static, and does not require static references, and does not require T to live forever. It actually means T must not be, or contain, any temporary references. In practice it means that only self-contained/owning types are allowed.

If the compiler suggests you to add 'static to a function argument, it's misleading you. It's a bad diagnostic that naively propagates from T: 'static rule somewhere. The compiler is trying to say that the argument must not be a reference. Usually you need to replace & with Arc, or &str with String, etc.

6 Likes

tl;dr

&'static T: this reference is valid for the entire lifetime of the program
T: 'static: this type may live forever (but doesn't need to)

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.