Устал от lazy_static? Rust 1.80 имеет более чистый путь
6 июня 2025 г.Rust предлагает разные способы инициализацииСкомпилируйте время инициализированопеременные. Недавно мне пришлось создать инициализованную переменную выполнения: существующие подходы не работают в этом случае. Я хочу описать несколько способов достичь этого в этом посте.
Константы
Язык ржавчины позволяет создавать константы. Доступны два ключевых слова:constиstaticПолем
Иногда определенное значение используется много раз во всей программе, и копировать его снова и снова может стать неудобным. Более того, не всегда возможно или желательно сделать его переменной, которая переносится на каждую функцию, которая в ней нуждается. В этих случаях
constКлючевое слово предоставляет удобную альтернативу дублированию кода:const THING: u32 = 0xABAD1DEA; let foo = 123 + THING;-Ключевое слово const
Статический элемент - это значение, которое действителен на всю продолжительность вашей программы (
'staticпродолжительность жизни).На поверхности,
staticПредметы кажутся очень похожими наconst: Оба содержат значение, оба требуют аннотации типа, и оба могут быть инициализированы только с постоянными функциями и значениями. Однако,staticзаметно отличаются тем, что они представляют место в памяти. Это означает, что у вас могут быть ссылки наstaticПредметы и потенциально даже изменяют их, делая их по существу глобальные переменные.Статические элементы не звонят
dropВ конце программы.Есть два типа
staticПредметы: те, которые объявляются в связи сmutКлючевое слово и те, кто без.-Ключевое слово статичное
Ни один из вышеперечисленных не работает сstructПолем
Я исправил:https://www.reddit.com/r/rust/comments/1l0uwzy/comment/mvgghb0/Полем
const REGEXP_WAREHOUSE_ENDPOINT: Regex = Regex::new(r"^WAREHOUSE__(?<index>\d)__ENDPOINT.*").unwrap();
Попытка составить предыдущую строку возвращает следующую:
error[E0015]: cannot call non-const fn `regex::Regex::new` in constants
|
6 | const REGEXP_WAREHOUSE_ENDPOINT: Regex = Regex::new(r"^WAREHOUSE__(?<index>\d)__ENDPOINT.*").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
То же самое происходит, если мы изменимсяconstкstaticПолем
error[E0015]: cannot call non-const fn `regex::Regex::new` in statics
--> src/config.rs:6:43
|
6 | static REGEXP_WAREHOUSE_ENDPOINT: Regex = Regex::new(r"^WAREHOUSE__(?<index>\d)__ENDPOINT.*").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
Нам нуженВремя выполнения инициализированопеременная дляstructПолем Ни одинconstниlazyработа; Время искать что -то другое.
Аlazy_staticящик
Когда вам что -то нужно, есть высокая вероятность того, что кто -то нуждается в этом раньше. Если повезет, они создали для этого ящик. Показательный примерlazy_staticЯщик обеспечивает решение.
Макрос для объявления лениво оцениваемой статики в ржавчине.
Используя этот макрос, можно иметь статику, которая требует выполнения кода во время выполнения, чтобы быть инициализированным. Это включает в себя все, что требует распределений кучи, таких как векторы или хеш-карты, а также все, что требует вычислений неконфекционных функций.
-Lazy_static Crate
Использование простое: мы завершаемstaticДекларация на макросе.
lazy_static! {
static ref REGEXP_WAREHOUSE_ENDPOINT: Regex = Regex::new(r"^WAREHOUSE__(?<index>\d)__ENDPOINT.*").unwrap();
}
Мы достигли того, что хотели. Тем не менее, мы можем добиться большего.
LazyLockза победу
Ржавчина 1.80 добавляетLazyLockПолемLazyLockявляется встроенной точной заменой дляlazy_staticмакро.
https://x.com/13erbse/status/1816491350235173228?embedable=true
ДокументацияLazyLockпросто:
pub struct LazyLock<T, F = fn() -> T> { /* private fields */ }Значение, которое инициализируется на первом доступе.
Этот тип представляет собой безопасную нить Lazycell, и он может использоваться в статике. Поскольку инициализация может быть вызвана из нескольких потоков, любой вызов из деревьев заблокирует вызову, если в настоящее время будет запущена другая подпрограмма инициализации.
-Лазилок
На этом этапе мы можем использовать его напрямую:
static REGEXP_WAREHOUSE_ENDPOINT: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"^WAREHOUSE__(?<index>\d)__ENDPOINT.*").unwrap());
OnceLock
В качестве альтернативы можно использоватьOnceLockот ржавчины 1.70.
pub struct OnceLock<T> { /* private fields */ }Примитив синхронизации, который может быть номинально записан только один раз.
Этот тип-безопасная потока
OnceCell, и может использоваться в статике. Во многих простых случаях вы можете использоватьLazyLock<T, F>Вместо этого, чтобы получить преимущества этого типа с меньшими усилиями:LazyLock<T, F>"Похоже"&TПотому что он инициализируется сFна Дереф! Где сияет в том, что Lazylock слишком прост, чтобы поддержать заданный корпус, так как Lazylock не допускает дополнительных входов на свою функцию после вызова после вызоваLazyLock::new(|| ...)Полем-Наступил
Использование совершенно другое:
static REGEXP_WAREHOUSE_ENDPOINT: OnceLock<Regex> = OnceLock::new(); //1
let endpoint = REGEXP_WAREHOUSE_ENDPOINT.get_or_init(
|| Regex::new(r"^WAREHOUSE__(?P<index>\d+)__ENDPOINT$").unwrap()); //2
endpoint.find("whatever").is_some() //3
- Создать
OnceLock - Получить или инициализировать переменную
- Используйте переменную
Краткое содержание
В этом посте мы описали несколько вариантов для создания ленивых инициализированных переменных. Раньше нам приходилось полагаться наlazy_staticящик. С Rust 1.80 мы можем заменить его наLazyLockПолем Если вам нужен дополнительный ввод послеLazyLock::new()ВOnceLockтвой друг.
Идти дальше:
- Ключевое слово const
- Lazy_static Crate
- Структура Lazylock
- Структура
Первоначально опубликовано вJava Geek1 июня 2025 года
Оригинал