How to make it global?

#[macro_use]
extern crate lazy_static;

#[derive(Debug)]
struct B {
    v: u8,
}

impl B {
    pub fn new(s: u8) -> B {
        B {
            v: s,
        }
    }
}

#[derive(Debug)]
pub struct A<'a> {
    pub values: &'a [B],
}

impl<'a> A<'_> {
    pub fn new(values: &'a [B]) -> A<'a> {
        A {
            values,
        }
    }
}

lazy_static! {
    pub static ref GLOBAL_VAR: [A<'static>; 1] = [
        A::new(&[B::new(3)]),
    ];
}

fn main() {
    for var in GLOBAL_VAR.iter() {
        println!("{:?}", var);
    }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0515]: cannot return value referencing temporary value
  --> src/main.rs:31:50
   |
31 |       pub static ref GLOBAL_VAR: [A<'static>; 1] = [
   |  __________________________________________________^
32 | |         A::new(&[B::new(3)]),
   | |                 ----------- temporary value created here
33 | |     ];
   | |_____^ returns a value referencing data owned by the current function

For more information about this error, try `rustc --explain E0515`.
error: could not compile `playground` (bin "playground") due to previous error

I'd like to know how to fix it. I'd like to solve it without Box like thing(something that using heap memory)

And why this code is work?

#[derive(Debug)]
pub struct A<'a> {
    pub values: &'a [u8],
}

impl<'a> A<'_> {
    pub fn new(values: &'a [u8]) -> A<'a> {
        A {
            values,
        }
    }
}

lazy_static! {
    pub static ref GLOBAL_VAR: [A<'static>; 1] = [
        A::new(&[1,2]),
    ];
}

I think it also have same problem.

And I have question that why Rust do not know array size if change GLOBAL_VAR type to [A<'static>]. I think the result of return value of expression is obviously 1.

You probably want to put B::new(3) into a separate lazy_static value and reference this in A::new.

&[1, 2] is subject to static promotion, that is, Rust puts it into the (hidden) static automatically. For the original example, this is strictly impossible, since B::new isn't const fn (and even if it was, compiler would not do this automatically AFAIK, since this approach would be complex and somewhat brittle).

Type [A<'static'>], like any [T], erases this information from compile-time (by moving it to runtime).

Thank you for super fast reply, and also very helpful!

Is there way that can do automatically B::new(3) to another lazy_static?

Because actually my code have a lot that kind of pattern, so move it by manually it is difficult work and chance for human error

I'd like to solve it without Box like thing(something that using heap memory)

You should seriously consider just using Vec. Once the lazy initialization has completed, Vec<T> costs no more than &[T] to access, and it is far easier to create.

If you need specifically the &[u8] type, then you can start with Vec and then call Vec::leak() to turn it into a static reference. (This does not create an actual memory leak because you only do it once — the GLOBAL_VAR's value will need to live forever no matter how you represent it.)

The reason I didn't use Vec is that I want initialize global variable at compile-time as a constance rather than run-time

Then you should not be using lazy_static at all, because lazy_static is for performing the initialization at run time (on first use). Use a plain static instead. You'll need to make your constructor functions const fn, but then this code will compile and actually be a compile-time initialization.

pub static GLOBAL_VAR: [A<'static>; 1] = [
    A::new(&[B::new(3)]),
];
2 Likes

I didn't catch that problem thank you.

I have another question about below code

This code have compile error on test2. But I think test2 is const function so as like test it believe it would can be compiled correctly but it isn't. Why it is not allowed and Is it possible to write simmilar code?

#[derive(Debug)]
struct A {
    a: u8,
}

const fn test() -> &'static A {
    & A {a: 3}
}

const fn test2(a: u8) -> &'static A {
    & A {a}
}

const fns are ordinary functions, they can be called at runtime. And in this case, created A can not be promoted to static, obviously, so implicitly creating &'static A (without some kind of explicit leaking) is impossible. Therefore, it's forbidden.