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
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).
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.
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 okcould do with its signature, such as the example that @jameseb7 posted, and since the signature of ok allows those, main does not compile.
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.
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.
'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.