Структура 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()); }