
Устал от 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 года
Оригинал