Was ist der beste Weg, um eine Struktur mit nur einer Instanziierung im System zu erstellen und zu verwenden? Ja, dies ist notwendig, es ist das OpenGL-Subsystem, und das Erstellen mehrerer Kopien davon und das Weitergeben überall würde Verwirrung stiften, anstatt es zu lindern.
Der Singleton muss so effizient wie möglich sein. Es scheint nicht möglich zu sein, ein beliebiges Objekt im statischen Bereich zu speichern, da es ein Objekt Vec
mit einem Destruktor enthält. Die zweite Option besteht darin, einen (unsicheren) Zeiger auf dem statischen Bereich zu speichern, der auf einen dem Heap zugewiesenen Singleton zeigt. Was ist der bequemste und sicherste Weg, dies zu tun, während die Syntax knapp bleibt?
Antworten:
Antwort ohne Antwort
Vermeiden Sie den globalen Zustand im Allgemeinen. Konstruieren Sie das Objekt stattdessen irgendwo früh (möglicherweise in
main
) und übergeben Sie dann veränderbare Verweise auf dieses Objekt an die Stellen, an denen es benötigt wird. Dies erleichtert normalerweise das Nachdenken über Ihren Code und erfordert nicht so viel Rückbiegen.Schauen Sie sich im Spiegel genau an, bevor Sie sich für globale veränderbare Variablen entscheiden. Es gibt seltene Fälle, in denen es nützlich ist. Deshalb lohnt es sich zu wissen, wie es geht.
Willst du noch einen machen ...?
Lazy-Static verwenden
Die faul-statische Kiste kann einen Teil der Plackerei beim manuellen Erstellen eines Singletons beseitigen. Hier ist ein global veränderlicher Vektor:
Wenn Sie das entfernen
Mutex
, haben Sie einen globalen Singleton ohne Veränderbarkeit.Sie können auch a
RwLock
anstelle von a verwendenMutex
, um mehrere gleichzeitige Leser zuzulassen.Einmal_Zelle verwenden
Die Once_cell- Kiste kann die mühsame manuelle Erstellung eines Singletons entlasten . Hier ist ein global veränderlicher Vektor:
Wenn Sie das entfernen
Mutex
, haben Sie einen globalen Singleton ohne Veränderbarkeit.Sie können auch a
RwLock
anstelle von a verwendenMutex
, um mehrere gleichzeitige Leser zuzulassen.Ein Sonderfall: Atomik
Wenn Sie nur einen ganzzahligen Wert verfolgen müssen, können Sie direkt ein Atom verwenden :
Manuelle, abhängigkeitsfreie Implementierung
Dies ist stark von der Rust 1.0-Implementierung
stdin
mit einigen Verbesserungen für das moderne Rust geprägt. Sie sollten sich auch die moderne Implementierung von ansehenio::Lazy
. Ich habe inline kommentiert, was jede Zeile tut.Dies druckt aus:
Dieser Code wird mit Rust 1.42.0 kompiliert. Die realen Implementierungen
Stdin
verwenden einige instabile Funktionen, um zu versuchen, den zugewiesenen Speicher freizugeben, was dieser Code nicht tut.Wirklich, Sie möchten wahrscheinlich ein
SingletonReader
Gerät erstellen,Deref
und müssenDerefMut
daher nicht in das Objekt eindringen und es selbst sperren.All diese Arbeiten erledigen Lazy-Static oder Once_cell für Sie.
Die Bedeutung von "global"
Bitte beachten Sie, dass Sie weiterhin den normalen Rust-Bereich und die Privatsphäre auf Modulebene verwenden können, um den Zugriff auf eine
static
oder einelazy_static
Variable zu steuern . Dies bedeutet, dass Sie es in einem Modul oder sogar innerhalb einer Funktion deklarieren können und außerhalb dieses Moduls / dieser Funktion nicht darauf zugreifen können. Dies ist gut für die Zugriffskontrolle:Die Variable ist jedoch immer noch global, da eine Instanz davon im gesamten Programm vorhanden ist.
quelle
void *
die dann an die Methoden jedes Moduls zurückgegeben werden. Dies ist ein typisches Erweiterungsmuster für C-Code. Wenn die Anwendung dies nicht zulässt und Sie es nicht ändern können, ist ein Singleton möglicherweise eine gute Lösung.lazy_static
Beispiel in Rust 1.24.1 getestet und es funktioniert genau. Hier gibt esexternal static
nirgendwo etwas. Vielleicht müssen Sie die Dinge an Ihrem Ende überprüfen, um sicherzustellen, dass Sie die Antwort vollständig verstanden haben.Verwenden Sie SpinLock für den globalen Zugriff.
Wenn Sie einen veränderlichen Status (NICHT Singleton) wünschen , finden Sie weitere Beschreibungen unter Was Sie in Rust nicht tun sollten .
Hoffe es ist hilfreich.
quelle
Beantwortung meiner eigenen doppelten Frage .
Cargo.toml:
Kistenwurzel (lib.rs):
Initialisierung (keine Notwendigkeit für einen unsicheren Block):
BEARBEITEN:
Es ist gelungen, das Problem mit Once_cell zu lösen, für das kein Makro erforderlich ist.
Cargo.toml:
square.rs:
quelle
lazy_static
und den neueren Antwortenonce_cell
. Das Markieren von Dingen als Duplikate in SO besteht darin, redundante Informationen zu vermeiden.