Есть ли чистый способ иметь глобальное изменяемое состояние в плагине Rust?
Единственный способ сделать это - небезопасная одноэлементная функция:
fn singleton() -> &'static mut HashSet<String> {
static mut hash_map: *mut HashSet<String> = 0 as *mut HashSet<String>;
let map: HashSet<String> = HashSet::new();
unsafe {
if hash_map == 0 as *mut HashSet<String> {
hash_map = mem::transmute(Box::new(map));
}
&mut *hash_map
}
}
Есть ли способ лучше? Возможно, мы могли бы сделать что-то в plugin_registrar
функционировать?
Под глобальным изменяемым состоянием я подразумеваю изменчивую переменную, которая может использоваться несколькими процедурными макросами и / или атрибутами.
Обновить:
Я пишу плагин компилятора, чтобы обеспечить sql!
процедурный макрос. у меня есть #[sql_table]
атрибут, который будет использоваться в структурах, чтобы я мог получить имя и столбцы таблицы SQL.
Мне нужно глобальное изменяемое состояние, чтобы сохранить имя и поля struct
в атрибуте, так что процедурный макрос может проверить, что все идентификаторы существуют.
1 ответ
lazy_static!
макрос может помочь с глобальным инициализатором, который не является статическим. https://crates.io/crates/lazy_static/ Это делает что-то похожее на ваш if hash_map == 0 as *mut HashSet<String>
, но заботится о гонке данных в случае, если более чем один поток пытается сделать это одновременно.
Что касается изменчивости, чтобы избежать новых гонок данных, вам придется как-то защитить ее, возможно, с Mutex
,
Все вместе:
#[macro_use] extern crate lazy_static;
use std::sync::Mutex;
use std::collections::HashSet;
lazy_static! {
static ref THINGS: Mutex<HashSet<String>> = Mutex::new(HashSet::new());
}
fn usage() {
// unwrap only fails if the lock is poisoned:
// if another thread panicked while holding the lock.
THINGS.lock().unwrap().insert("thing".to_owned())
}