Как лучше всего создать и использовать структуру только с одним экземпляром в системе? Да, это необходимо, это подсистема OpenGL, и создание нескольких ее копий и их распространение повсюду добавят путаницы, а не уменьшат ее.
Синглтон должен быть максимально эффективным. Кажется невозможным хранить произвольный объект в статической области, поскольку он содержит Vec
деструктор. Второй вариант - сохранить (небезопасный) указатель в статической области, указывающий на выделенный синглтон в куче. Каков наиболее удобный и безопасный способ сделать это с кратким синтаксисом?
Ответы:
Ответ без ответа
Избегайте глобального состояния в целом. Вместо этого создайте объект где-нибудь на раннем этапе (возможно, внутри
main
), а затем передайте изменяемые ссылки на этот объект в места, где он нужен. Обычно это облегчает понимание вашего кода и не требует большого изгиба назад.Внимательно посмотрите на себя в зеркало, прежде чем решить, что вам нужны глобальные изменяемые переменные. В редких случаях это полезно, поэтому стоит знать, как это сделать.
Все еще хотите сделать ...?
Использование lazy-static
Ленивые статическая обрешетка может забрать некоторые из нудного создания синглтона вручную. Вот глобальный изменчивый вектор:
Если вы удалите,
Mutex
то у вас будет глобальный синглтон без какой-либо изменчивости.Вы также можете использовать
RwLock
вместо a,Mutex
чтобы разрешить одновременное использование нескольких читателей.Использование Once_cell
Once_cell обрешетка может забрать некоторые из нудного создания синглтона вручную. Вот глобальный изменчивый вектор:
Если вы удалите,
Mutex
то у вас будет глобальный синглтон без какой-либо изменчивости.Вы также можете использовать
RwLock
вместо a,Mutex
чтобы разрешить одновременное использование нескольких читателей.Особый случай: атомика
Если вам нужно отслеживать только целочисленное значение, вы можете напрямую использовать атомарное :
Ручная реализация без зависимостей
Это сильно заимствовано из реализации Rust 1.0
stdin
с некоторыми настройками для современного Rust. Также стоит посмотреть на современную реализациюio::Lazy
. Я прокомментировал, что делает каждая строка.Это распечатывает:
Этот код компилируется с Rust 1.42.0. Реальные реализации
Stdin
используют некоторые нестабильные функции, чтобы попытаться освободить выделенную память, чего не делает этот код.На самом деле, вы, вероятно , хотите , чтобы
SingletonReader
реализоватьDeref
иDerefMut
поэтому вы не должны совать в объект и зафиксировать его самостоятельно.Вся эта работа - это то, что делают за вас lazy-static или once_cell.
Значение слова «глобальный»
Обратите внимание, что вы по-прежнему можете использовать обычную область видимости Rust и конфиденциальность на уровне модуля для управления доступом к переменной
static
илиlazy_static
. Это означает, что вы можете объявить его в модуле или даже внутри функции, и он не будет доступен за пределами этого модуля / функции. Это хорошо для контроля доступа:Однако переменная по-прежнему является глобальной, поскольку существует один ее экземпляр во всей программе.
источник
void *
которые затем передаются обратно в методы каждого модуля. Это типичный шаблон расширения для кода C. Если приложение не позволяет это сделать и вы не можете его изменить, то да, синглтон может быть хорошим решением.lazy_static
пример в Rust 1.24.1, и он работает точно. Здесьexternal static
нигде нет . Возможно, вам нужно кое-что проверить, чтобы убедиться, что вы полностью поняли ответ.Используйте SpinLock для глобального доступа.
Если вам нужно изменяемое состояние (НЕ Singleton), см. Дополнительные описания в разделе « Чего не следует делать в Rust» .
Надеюсь, это поможет.
источник
Отвечая на мой собственный повторяющийся вопрос .
Cargo.toml:
Корень ящика (lib.rs):
Инициализация (небезопасный блок не нужен):
РЕДАКТИРОВАТЬ:
Удалось решить с помощью once_cell, для которого не нужен макрос.
Cargo.toml:
square.rs:
источник
lazy_static
и более новымиonce_cell
. Смысл маркировки вещей как дубликатов на SO - избежать избыточной информации.