Структура LazyLock

#![allow(unused)]
fn main() {
pub struct LazyLock<T, F = fn() -> T> { /* приватные поля */ }
}

Значение, которое инициализируется при первом доступе.

Для совместного использования между потоками, LazyLock должен быть обернут в примитив синхронизации, такой как Arc.

Пример

use std::sync::LazyLock;

static LAZY: LazyLock<String> = LazyLock::new(|| {
    "Hello, World!".to_string()
});

fn main() {
    println!("{}", *LAZY); // Печатает "Hello, World!"
}

Методы

pub const fn new(f: F) -> LazyLock<T, F>

Создает новый экземпляр LazyLock с заданной функцией инициализации.

Пример

#![allow(unused)]
fn main() {
use std::sync::LazyLock;

let lazy = LazyLock::new(|| 92);

// Доступ к значению инициализирует его
assert_eq!(*lazy, 92);
}

pub fn into_inner(this: LazyLock<T, F>) -> Result<T, F>

Потребляет этот LazyLock, возвращая сохраненное значение.

Возвращает Ok(value), если LazyLock уже инициализирован, и Err(f), если он еще не инициализирован.

Пример

#![allow(unused)]
fn main() {
use std::sync::LazyLock;

let lazy = LazyLock::new(|| 92);

assert_eq!(LazyLock::into_inner(lazy).unwrap(), 92);
}

pub fn force(this: &LazyLock<T, F>) -> &T where F: FnOnce() -> T,

Принудительно вычисляет и возвращает ссылку на значение.

Это эквивалентно разыменованию, но более явное.

Пример

#![allow(unused)]
fn main() {
use std::sync::LazyLock;

let lazy = LazyLock::new(|| 92);

// Принудительная инициализация
assert_eq!(LazyLock::force(&lazy), &92);

// Или просто разыменование
assert_eq!(*lazy, 92);
}

pub fn get(this: &LazyLock<T, F>) -> Option<&T>

Получает ссылку на результат вычисления, если он уже инициализирован.

Возвращает Some, если LazyLock уже инициализирован, и None в противном случае.

Пример

#![allow(unused)]
fn main() {
use std::sync::LazyLock;

let lazy = LazyLock::new(|| 92);

// Еще не инициализирован
assert_eq!(LazyLock::get(&lazy), None);

// После доступа инициализируется
let _ = *lazy;
assert_eq!(LazyLock::get(&lazy), Some(&92));
}

Реализации Trait

impl<T, F> Deref for LazyLock<T, F> where F: FnOnce() -> T,

type Target = T

Результирующий тип после разыменования.

fn deref(&self) -> &T

Разыменовывает значение.

При первом вызове этого метода будет вызвана функция инициализации для вычисления значения. Последующие вызовы вернут кэшированное значение.

Пример

#![allow(unused)]
fn main() {
use std::sync::LazyLock;

let lazy = LazyLock::new(|| {
    println!("Инициализация значения");
    42
});

// При первом доступе печатает "Инициализация значения"
println!("{}", *lazy); // 42

// При последующих доступах значение берется из кэша
println!("{}", *lazy); // 42
}

impl<T, F> DerefMut for LazyLock<T, F> where F: FnOnce() -> T,

fn deref_mut(&mut self) -> &mut T

Разыменовывает значение с возможностью изменения.

При первом вызове этого метода будет вызвана функция инициализации для вычисления значения. Последующие вызовы вернут кэшированное значение.

Пример

#![allow(unused)]
fn main() {
use std::sync::LazyLock;

let mut lazy = LazyLock::new(|| vec![1, 2, 3]);

// Инициализирует и получает изменяемую ссылку
lazy.push(4);
assert_eq!(*lazy, vec![1, 2, 3, 4]);
}

impl<T, F> Debug for LazyLock<T, F> where T: Debug,

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Форматирует значение с использованием заданного форматировщика.

Пример

#![allow(unused)]
fn main() {
use std::sync::LazyLock;

let lazy = LazyLock::new(|| 42);
println!("{:?}", lazy); // Печатает отладочное представление
}

impl<T, F> Default for LazyLock<T, F> where F: Default,

fn default() -> LazyLock<T, F>

Возвращает "значение по умолчанию" для типа.

Пример

#![allow(unused)]
fn main() {
use std::sync::LazyLock;

#[derive(Default)]
struct MyInit;

let lazy: LazyLock<i32, _> = LazyLock::default();
}

impl<T, F: FnOnce() -> T> From<F> for LazyLock<T, F>

fn from(f: F) -> LazyLock<T, F>

Создает новый LazyLock из функции инициализации.

Пример

#![allow(unused)]
fn main() {
use std::sync::LazyLock;

let lazy = LazyLock::from(|| "hello".to_string());
assert_eq!(*lazy, "hello");
}

Автоматические реализации Trait

impl<T, F> RefUnwindSafe for LazyLock<T, F> where F: RefUnwindSafe, T: RefUnwindSafe,

impl<T, F> Send for LazyLock<T, F> where F: Send, T: Send,

impl<T, F> Sync for LazyLock<T, F> where F: Sync, T: Sync,

impl<T, F> Unpin for LazyLock<T, F> where F: Unpin, T: Unpin,

impl<T, F> UnwindSafe for LazyLock<T, F> where F: UnwindSafe, T: UnwindSafe,

Blanket реализации

impl<T> Any for T where T: 'static + ?Sized,

impl<T> Borrow<T> for T where T: ?Sized,

impl<T> BorrowMut<T> for T where T: ?Sized,

impl<T> From<T> for T

impl<T, U> Into<U> for T where U: From<T>,

impl<T> ToOwned for T where T: Clone,

impl<T, U> TryFrom<U> for T where U: Into<T>,

impl<T, U> TryInto<U> for T where U: TryFrom<T>,

Примеры использования

Статическая ленивая инициализация

use std::sync::LazyLock;
use std::collections::HashMap;

static HASHMAP: LazyLock<HashMap<i32, String>> = LazyLock::new(|| {
    println!("Инициализация HashMap");
    let mut m = HashMap::new();
    m.insert(13, "Spica".to_string());
    m.insert(74, "Hoyten".to_string());
    m
});

fn main() {
    println!("Готов");
    println!("{:?}", *HASHMAP);
}

Ленивая инициализация с захватом переменных

use std::sync::LazyLock;

fn create_lazy() -> LazyLock<Vec<i32>> {
    let base_value = 10;
    LazyLock::new(|| {
        vec![base_value, base_value * 2, base_value * 3]
    })
}

fn main() {
    let lazy_vec = create_lazy();
    assert_eq!(*lazy_vec, vec![10, 20, 30]);
}

Использование с изменяемым доступом

#![allow(unused)]
fn main() {
use std::sync::LazyLock;

let mut lazy_counter = LazyLock::new(|| 0);

// Увеличиваем счетчик после инициализации
*lazy_counter += 1;
assert_eq!(*lazy_counter, 1);
}

Проверка состояния инициализации

#![allow(unused)]
fn main() {
use std::sync::LazyLock;

let lazy_value = LazyLock::new(|| 42);

// Проверяем, инициализирован ли уже
assert!(LazyLock::get(&lazy_value).is_none());

// Инициализируем доступом
let _ = *lazy_value;

// Теперь инициализирован
assert!(LazyLock::get(&lazy_value).is_some());
}