¿Cuál es la mejor manera de crear y usar una estructura con solo una instanciación en el sistema? Sí, esto es necesario, es el subsistema OpenGL, y hacer múltiples copias de esto y pasarlo por todas partes agregaría confusión, en lugar de aliviarla.
El singleton debe ser lo más eficiente posible. No parece posible almacenar un objeto arbitrario en el área estática, ya que contiene un Vec
con un destructor. La segunda opción es almacenar un puntero (inseguro) en el área estática, apuntando a un singleton asignado al montón. ¿Cuál es la forma más conveniente y segura de hacer esto, manteniendo la sintaxis concisa?
Respuestas:
Respuesta sin respuesta
Evite el estado global en general. En su lugar, construya el objeto en algún lugar temprano (tal vez adentro
main
), luego pase referencias mutables a ese objeto en los lugares que lo necesitan. Por lo general, esto hará que sea más fácil razonar sobre el código y no requerirá tanto hacer lo imposible.Mírese con atención en el espejo antes de decidir que quiere variables mutables globales. Hay casos raros en los que es útil, por eso vale la pena saber cómo hacerlo.
¿Todavía quieres hacer uno ...?
Usando lazy-static
La caja estática perezosa puede eliminar parte del trabajo pesado de crear manualmente un singleton. Aquí hay un vector mutable global:
Si elimina el,
Mutex
entonces tiene un singleton global sin ninguna mutabilidad.También puede utilizar a en
RwLock
lugar de aMutex
para permitir varios lectores simultáneos.Usando once_cell
La caja once_cell puede eliminar parte de la monotonía de crear manualmente un singleton. Aquí hay un vector mutable global:
Si elimina el,
Mutex
entonces tiene un singleton global sin ninguna mutabilidad.También puede utilizar a en
RwLock
lugar de aMutex
para permitir varios lectores simultáneos.Un caso especial: atómico
Si solo necesita rastrear un valor entero, puede usar directamente un valor atómico :
Implementación manual y sin dependencias
Esto se debe en gran medida a la implementación de Rust 1.0
stdin
con algunos ajustes para el Rust moderno. También debe mirar la implementación moderna deio::Lazy
. He comentado en línea con lo que hace cada línea.Esto imprime:
Este código se compila con Rust 1.42.0. Las implementaciones reales de
Stdin
usan algunas características inestables para intentar liberar la memoria asignada, lo que este código no hace.Realmente, probablemente querrá hacer un
SingletonReader
implementoDeref
y,DerefMut
por lo tanto, no tendrá que empujar el objeto y bloquearlo usted mismo.Todo este trabajo es lo que lazy-static o once_cell hacen por ti.
El significado de "global"
Tenga en cuenta que aún puede usar el alcance normal de Rust y la privacidad a nivel de módulo para controlar el acceso a una variable
static
olazy_static
. Esto significa que puede declararlo en un módulo o incluso dentro de una función y no será accesible fuera de ese módulo / función. Esto es bueno para controlar el acceso:Sin embargo, la variable sigue siendo global en el sentido de que hay una instancia de ella que existe en todo el programa.
fuente
void *
que luego se devuelven a los métodos de cada módulo. Este es un patrón de extensión típico para el código C. Si la aplicación no lo permite y no puede cambiarlo, entonces sí, un singleton puede ser una buena solución.lazy_static
ejemplo en Rust 1.24.1 y funciona exactamente. No hay ningúnexternal static
lugar aquí. Tal vez necesite verificar las cosas por su parte para asegurarse de que ha entendido la respuesta completamente.Utilice SpinLock para acceso global.
Si desea un estado mutable (NO Singleton), consulte Qué no hacer en Rust para obtener más descripciones.
Espero que sea de ayuda.
fuente
Respondiendo a mi propia pregunta duplicada .
Cargo.toml:
Raíz de caja (lib.rs):
Inicialización (sin necesidad de bloqueo inseguro):
EDITAR:
Se las arregló para resolverlo con once_cell, que no necesita una macro.
Cargo.toml:
cuadrados.rs:
fuente
lazy_static
y las más nuevasonce_cell
. El objetivo de marcar cosas como duplicadas en SO es evitar tener información redundante.