Unendliche Anwendungen von Go's Leerer Struktur
Grace Collins
Solutions Engineer · Leapcell

Vorwort
In der Go-Programmiersprache gibt es eine spezielle Verwendung, die viele Leute verwirren kann – die leere Struktur struct{}
. In diesem Artikel werde ich eine detaillierte Erklärung von Go's leerer Struktur geben. Bereit? Holen Sie sich Ihr Lieblingsgetränk oder Ihren Tee, und los geht's.
Was ist eine leere Struktur
Eine Struktur, die keine Felder enthält, wird als leere Struktur bezeichnet. Sie kann auf folgende zwei Arten definiert werden:
- Anonyme leere Struktur
var e struct{}
- Benannte leere Struktur
type EmptyStruct struct{} var e EmptyStruct
Eigenschaften von leeren Strukturen
Leere Strukturen haben die folgenden Haupteigenschaften:
- Keine Speicherzuweisung
- Gleiche Adresse
- Zustandslose
Keine Speicherzuweisung
Leere Strukturen belegen keinen Speicherplatz. Dies macht sie sehr nützlich für die Speicheroptimierung. Betrachten wir ein Beispiel, um zu überprüfen, ob sie wirklich keinen Speicher belegen:
package main import ( "fmt" "unsafe" ) func main() { var a int var b string var e struct{} fmt.Println(unsafe.Sizeof(a)) // 4 fmt.Println(unsafe.Sizeof(b)) // 8 fmt.Println(unsafe.Sizeof(e)) // 0 }
Wie die Ausgabe zeigt, beträgt die Speichergröße einer leeren Struktur 0.
Gleiche Adresse
Egal wie viele leere Strukturen Sie erstellen, sie alle zeigen auf dieselbe Adresse.
package main import ( "fmt" ) func main() { var e struct{} var e2 struct{} fmt.Printf("%p\n", &e) // 0x90b418 fmt.Printf("%p\n", &e2) // 0x90b418 fmt.Println(&e == &e2) // true }
Zustandslose
Da eine leere Struktur keine Felder enthält, kann sie keinen Zustand enthalten. Dies macht sie sehr nützlich für die Darstellung zustandsloser Objekte oder Bedingungen.
Warum kein Speicher und gleiche Adresse?
Um zu verstehen, warum leere Strukturen keine Größe haben und dieselbe Adresse teilen, müssen wir uns mit dem Go-Quellcode befassen.
/go/src/runtime/malloc.go
// base address for all 0-byte allocations var zerobase uintptr func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { // ... if size == 0 { return unsafe.Pointer(&zerobase) } // ...
Laut diesem Auszug aus malloc.go
gibt die Funktion, wenn die Größe des zuzuweisenden Objekts 0 ist, einen Zeiger auf zerobase
zurück. zerobase
ist eine Basisadresse, die für die Zuweisung von Null-Byte-Objekten verwendet wird und keinen tatsächlichen Speicherplatz belegt.
Anwendungsszenarien von leeren Strukturen
Leere Strukturen werden hauptsächlich in den folgenden drei Szenarien verwendet:
- Implementierung einer Set-Datenstruktur
- Verwendung als Signale in Kanälen
- Verwendung als Methodenempfänger
Implementierung einer Set-Datenstruktur
Obwohl Go keinen eingebauten Set-Typ hat, können wir einen mit dem Map-Typ implementieren. Da Map-Schlüssel eindeutig sind, können wir Elemente als Schlüssel speichern, und da die Werte nicht wichtig sind, verwenden wir leere Strukturen als Werte, um Speicher zu sparen.
package main import "fmt" type Set[K comparable] map[K]struct{} func (s Set[K]) Add(val K) { s[val] = struct{}{} } func (s Set[K]) Remove(val K) { delete(s, val) } func (s Set[K]) Contains(val K) bool { _, ok := s[val] return ok } func main() { set := Set[string]{} set.Add("Leapcell") fmt.Println(set.Contains("Leapcell")) // true set.Remove("Leapcell") fmt.Println(set.Contains("Leapcell")) // false }
Verwendung als Kanalsignale
Leere Strukturen werden oft für die Signalisierung zwischen Goroutinen verwendet, insbesondere wenn wir uns nicht um die tatsächlichen Daten kümmern, die im Kanal übertragen werden, sondern nur um das Signal. Zum Beispiel können wir einen leeren Strukturkanal verwenden, um eine Goroutine zu benachrichtigen, die Arbeit einzustellen:
package main import ( "fmt" "time" ) func main() { quit := make(chan struct{}) go func() { // Simulate work fmt.Println("Working...") time.Sleep(3 * time.Second) // Send quit signal close(quit) }() // Block and wait for quit signal to close <-quit fmt.Println("Quit signal received, exiting...") }
In diesem Beispiel wird ein quit
-Kanal erstellt, und eine separate Goroutine simuliert etwas Arbeit. Nach Abschluss der Arbeit schließt sie den quit
-Kanal, um den Ausgang zu signalisieren. Die Hauptfunktion blockiert bei <-quit
, bis sie das Signal empfängt, druckt dann eine Meldung und beendet sich.
Da der Kanal den leeren Strukturtyp verwendet, verursacht er keinen zusätzlichen Speicheraufwand.
In der Go-Standardbibliothek hat die Context
-Schnittstelle des context
-Pakets eine Done()
-Methode, die einen Kanal zurückgibt, der verwendet wird, um den Abschlussstatus von Operationen zu signalisieren. Dieser zurückgegebene Kanal verwendet eine leere Struktur als seinen Typ.
type Context interface { Deadline() (deadline time.Time, ok bool) Done() <-chan struct{} Err() error Value(key any) any }
Verwendung als Methodenempfänger
Manchmal müssen wir eine Gruppe von Methoden definieren (normalerweise um eine Schnittstelle zu implementieren), müssen aber keine Daten in der Implementierung speichern. In solchen Fällen können wir eine leere Struktur verwenden:
type Person interface { SayHello() Sleep() } type LPC struct{} func (c LPC) SayHello() { fmt.Println("[Leapcell] Hello") } func (c LPC) Sleep() { fmt.Println("[Leapcell] Sleeping...") }
Dieses Beispiel definiert eine Schnittstelle Person
und eine Struktur LPC
und implementiert die Schnittstelle Person
mit den Methoden SayHello
und Sleep
.
Da LPC
eine leere Struktur ist, verursacht sie keinen zusätzlichen Speicheraufwand.
Zusammenfassung
In diesem Artikel haben wir zunächst das Konzept und die Definitionen von leeren Strukturen in der Go-Sprache vorgestellt, die auf zwei Arten definiert werden können.
Dann haben wir die Eigenschaften leerer Strukturen untersucht, einschließlich ihrer null Speicherbelegung und der Tatsache, dass mehrere Variablen dieses Typs dieselbe Adresse teilen.
Als Nächstes sind wir tiefer in den Quellcode eingetaucht und haben untersucht, warum leere Strukturen in Go keinen Speicher und dieselbe Adresse haben. Der Grund dafür ist, dass Go einen Zeiger auf zerobase
zurückgibt, wenn die Größe des zuzuweisenden Objekts (size
) 0 ist.
Schließlich haben wir drei Anwendungsfälle für leere Strukturen aufgelistet und einige gängige reale Szenarien mit Codebeispielen demonstriert, darunter:
- Implementieren eines Sets mit einem
map[K]struct{}
- Verwenden leerer Strukturen für die Signalisierung in Kanälen
- Verwenden leerer Strukturen als Empfänger, wenn keine Datenspeicherung erforderlich ist
Wir sind Leapcell, Ihre erste Wahl für das Hosten von Go-Projekten.
Leapcell ist die Serverless-Plattform der nächsten Generation für Webhosting, asynchrone Aufgaben und Redis:
Multi-Sprachen-Unterstützung
- Entwickeln Sie mit Node.js, Python, Go oder Rust.
Stellen Sie unbegrenzt viele Projekte kostenlos bereit
- Zahlen Sie nur für die Nutzung – keine Anfragen, keine Gebühren.
Unschlagbare Kosteneffizienz
- Pay-as-you-go ohne Leerlaufgebühren.
- Beispiel: 25 $ unterstützen 6,94 Millionen Anfragen bei einer durchschnittlichen Antwortzeit von 60 ms.
Optimierte Entwicklererfahrung
- Intuitive Benutzeroberfläche für mühelose Einrichtung.
- Vollautomatische CI/CD-Pipelines und GitOps-Integration.
- Echtzeitmetriken und -protokollierung für umsetzbare Erkenntnisse.
Mühelose Skalierbarkeit und hohe Leistung
- Automatische Skalierung zur einfachen Bewältigung hoher Gleichzeitigkeit.
- Null Betriebsaufwand – konzentrieren Sie sich einfach auf das Bauen.
Erfahren Sie mehr in der Dokumentation!
Folgen Sie uns auf X: @LeapcellHQ