Rusty Spotted
Rusty Spotted

Reputation: 91

Const variable returns two different values

Today I did some tests on the nightly module std::lazy. It works well in local variable. However, when I defined a const variable, it gave me two different values. Seems the Colsure is called multiple times.

#![feature(once_cell)]
use rand::Rng; // 0.8.4
use std::lazy::Lazy;

const CONST_LAZY: Lazy<i32> = Lazy::new(|| rand::thread_rng().gen::<i32>());

fn main() {
    let local_lazy: Lazy<i32> = Lazy::new(|| rand::thread_rng().gen::<i32>());
    println!("{}", *local_lazy); // -1475423855
    println!("{}", *local_lazy); // -1475423855

    println!("{}", *CONST_LAZY); // 1975106939
    println!("{}", *CONST_LAZY); // -1848043613
}

Upvotes: 8

Views: 382

Answers (1)

Masklinn
Masklinn

Reputation: 42492

This is my code, can anyone tell me why?

Because you're confusing const and static.

Per the official documentation:

A constant item is an optionally named constant value which is not associated with a specific memory location in the program. Constants are essentially inlined wherever they are used, meaning that they are copied directly into the relevant context when used. This includes usage of constants from external crates, and non-Copy types. References to the same constant are not necessarily guaranteed to refer to the same memory address.

(note that the phrasing of the last sentence indicates consts could be promoted to statics and share a memory address, but there's no guarantee there, and while statics can be inlined it probably should not be observable through safe rust so should mostly be irrelevant).

In essence, your snippet is semantically equivalent to:

#![feature(once_cell)]
use rand::Rng; // 0.8.4
use std::lazy::Lazy;

fn main() {
    let local_lazy: Lazy<i32> = Lazy::new(|| rand::thread_rng().gen::<i32>());
    println!("{}", *local_lazy);
    println!("{}", *local_lazy);

    println!("{}", *Lazy::new(|| rand::thread_rng().gen::<i32>()));
    println!("{}", *Lazy::new(|| rand::thread_rng().gen::<i32>()));
}

That is also why it compiles at all, as Lazy is not thread-safe, and thus an actual global (a static) will not compile as it could be shared between threads.

Upvotes: 10

Related Questions