Since v1.51, const generic feature was officially released.
static
and const
static
Rust provides a ‘global variable’ sort of facility in static items. They’re similar to constants, but static items aren’t inlined upon use. This means that there is only one instance for each value, and it’s at a fixed location in memory.
const
Constants live for the entire lifetime of a program. More specifically, constants in Rust have no fixed address in memory. This is because they’re effectively inlined to each place that they’re used. References to the same constant are not necessarily guaranteed to refer to the same memory address for this reason.
lazy-static
Sometimes I wanted to calculate some value and store it as a static variable BEFORE entering main function.
The standard Rust doesn’t provide such feature, so I need to use lazy_static
crate.
macro for declaring lazily evaluated statics in Rust.
Using this macro, it is possible to have
statics
that require code to be executed at runtime in order to be initialized.
It’s super compact but useful.
https://www.youtube.com/watch?v=Vw8BFScm0K0
const function could be used for initialization, but as of Oct.2.2022, const function block doesn’t support unwrap
.
https://github.com/rust-lang/rust/issues/7493
#[derive(Debug)]
struct StackVector<const N: usize> {
data: [f64; N],
size: usize
}
impl<const N: usize> StackVector<N> {
fn new() -> Self {
StackVector {
data: [0. ;N],
size: N
}
}
}
fn main() {
let x = StackVector::<6>::new();
println!("{:?}", x);
// StackVector { data: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], size: 6 }
// The type is `StackVector<6_usize>`
}
As a value of const
is determined at compile time (because it is inlined), the value of const
should be decided at compile time.
An user input CAN’T be const
.
The following code isn’t compiled:
use std::io;
#[derive(Debug)]
struct StackVector<const N: usize> {
data: [f64; N],
size: usize
}
impl<const N: usize> StackVector<N> {
fn new() -> Self {
StackVector {
data: [0. ;N],
size: N
}
}
}
fn main() {
let nrows: usize;
let mut input = String::new();
println!("Input the number of rows:");
io::stdin()
.read_line(&mut input)
.expect("Failed to read line");
let trimmed = input.trim();
match trimmed.parse::<usize>() {
Ok(i) => {
nrows = i;
},
Err(..) => panic!(),
};
let x = StackVector::<nrows>::new();
println!("{:?}", x);
}
Here is the compile error:
error[E0435]: attempt to use a non-constant value in a constant
--> src/main.rs:33:27
|
19 | let nrows: usize;
| --------- help: consider using `const` instead of `let`: `const nrows`
...
33 | let x = StackVector::<nrows>::new();
| ^^^^^ non-constant value
As a work around, I came up with the idea with lazy_static
, but there is no compatibility between const
and static
for const generics.
So when you change the type to static, it returns error as follows:
error[E0013]: constants cannot refer to statics
--> src/main.rs:55:22
|
55 | let A = Matrix::<n, m>::new();
| ^
|
= help: consider extracting the value of the `static` to a `const`, and referring to that
`
https://blog.rust-lang.org/2021/02/26/const-generics-mvp-beta.html#current-restrictions