Initialize mutable array with size determined by lazy_static math expression

This is my first Rust program, so please bare with me. I am baffled at how something so simple can stop me dead in my tracks with Rust, so I'm sure there's another way to do this I haven't thought of. I recently found "lazy_static" which I thought would be my saving grace, but Rust seems dead set on me not being able to use HILBERT_MAX as a way to initialize the size of a mutable array.

I've stripped the program to the essence of the problem. Should be fairly obvious what I'm trying to do here. Any suggestions for a Rust newbie here?

extern crate num;

#[macro_use]
extern crate lazy_static;

static ORDER: u8 = 9;

// http://rust-lang-nursery.github.io/lazy-static.rs/lazy_static/index.html
lazy_static! {
    static ref HILBERT_MAX_REF: usize = num::pow(4 as usize, (ORDER-1) as usize);
}

const HILBERT_MAX: usize = *HILBERT_MAX_REF;

fn main() {
    let mut colors: [[u8; 4]; HILBERT_MAX] = [[0,0,0,0]; HILBERT_MAX];
}

The error produced is:

error[E0080]: constant evaluation error
  --> main.rs:13:28
   |
13 | const HILBERT_MAX: usize = *HILBERT_MAX_REF;
   |                            ^^^^^^^^^^^^^^^^ unimplemented constant expression: deref operation
   |
note: for array length here
  --> main.rs:16:31
   |
16 |     let mut colors: [[u8; 4]; HILBERT_MAX] = [[0,0,0,0]; HILBERT_MAX];
   |                               ^^^^^^^^^^^

error[E0080]: constant evaluation error
  --> main.rs:13:28
   |
13 | const HILBERT_MAX: usize = *HILBERT_MAX_REF;
   |                            ^^^^^^^^^^^^^^^^ unimplemented constant expression: deref operation
   |
note: for repeat count here
  --> main.rs:16:58
   |
16 |     let mut colors: [[u8; 4]; HILBERT_MAX] = [[0,0,0,0]; HILBERT_MAX];
   |                                                          ^^^^^^^^^^^

error: aborting due to 2 previous errors

const and static define compile-time constants, but dereferencing happens at run-time. That's why rustc complains with

unimplemented constant expression: deref operation

Keep in mind that lazy_static variables are initialised at run-time, not compile-time, so there's no way for rustc to know the result of *HILBERT_MAX_REF.

In any case, Rust doesn't (yet) support dynamic stack-allocated arrays, so you'll need to use a Vec here:

extern crate num;

#[macro_use]
extern crate lazy_static;

static ORDER: u8 = 9;

// http://rust-lang-nursery.github.io/lazy-static.rs/lazy_static/index.html
lazy_static! {
    static ref HILBERT_MAX_REF: usize = num::pow(4 as usize, (ORDER-1) as usize);
}

fn main() {
    let _ = vec![[0, 0, 0, 0]; *HILBERT_MAX_REF];
}
2 Likes

It works if you write it without pow:

const ORDER: u8 = 9;
const HILBERT_MAX: usize = 1 << 2 * (ORDER - 1);

fn main() {
    let mut colors: [[u8; 4]; HILBERT_MAX] = [[0,0,0,0]; HILBERT_MAX];
}
3 Likes

Both great answers! Thank you :slight_smile: