Die Wahl zwischen make und new in Go
Daniel Hayes
Full-Stack Engineer · Leapcell

Go bietet zwei häufig verwendete Möglichkeiten, Speicher zu reservieren: make und new. Obwohl beide zur Speicherreservierung verwendet werden, sind ihre Rollen und Anwendungsszenarien recht unterschiedlich. Das Verständnis der Unterschiede zwischen diesen beiden ist entscheidend für das Schreiben von effizientem und wartbarem Go-Code. Dieser Artikel analysiert gründlich die Unterschiede zwischen make und new, ihre geeigneten Szenarien und bietet einige Anwendungstipps.
Grundlegende Unterschiede zwischen make und new
new: Erstellt Nullwert von Zeigertypen
new ist ein Schlüsselwort in Go, das für die Speicherreservierung verwendet wird. Seine Funktion besteht darin, einen Speicherblock für einen Typ zu reservieren und einen Zeiger auf diesen Speicher zurückzugeben. Der von new reservierte Speicher wird mit dem Nullwert des Typs initialisiert.
Beispiel: Verwendung von new
package main import "fmt" func main() { var p *int = new(int) fmt.Println(*p) // Ausgabe: 0, der von `new` für int reservierte Speicher wird mit dem Nullwert initialisiert }
- Rückgabetyp:
newgibt einen Zeiger auf den Typ zurück. - Nullwert-Initialisierung:
newinitialisiert den reservierten Speicher mit dem Nullwert des Typs. Für den Typintist der Nullwert beispielsweise0; für den Typstringist es ein leerer String"".
make: Initialisiert Slices, Maps und Channels
make ist eine spezielle integrierte Funktion in Go, die speziell zur Initialisierung von drei integrierten Datentypen verwendet wird: Slice, Map und Channel. Im Gegensatz zu new gibt make keinen Zeiger auf den reservierten Speicher zurück, sondern das initialisierte Objekt selbst.
Beispiel: Verwendung von make
package main import "fmt" func main() { // Slice initialisieren s := make([]int, 5) fmt.Println(s) // Ausgabe: [0 0 0 0 0] // Map initialisieren m := make(map[string]int) m["age"] = 30 fmt.Println(m) // Ausgabe: map[age:30] // Channel initialisieren ch := make(chan int, 2) ch <- 1 fmt.Println(<-ch) // Ausgabe: 1 }
- Rückgabetyp:
makegibt das Objekt selbst (Slice, Map oder Channel) zurück, nicht einen Zeiger. - Speicherreservierung und -initialisierung:
makereserviert nicht nur Speicher, sondern initialisiert auch die Datenstruktur selbst. Bei der Initialisierung eines Slices reserviertmakebeispielsweise das zugrunde liegende Array und legt seine Länge und Kapazität fest.
Zusammenfassung der wichtigsten Unterschiede
-
Zweck:
new: Reserviert Speicher und gibt einen Zeiger auf den Typ zurück.make: Initialisiert und gibt ein Slice-, Map- oder Channel-Objekt zurück.
-
Rückgabewert:
new: Gibt einen Zeiger auf den Typ zurück.make: Gibt das initialisierte Objekt selbst zurück.
-
Anwendbare Typen:
new: Alle Typen.make: Slice, Map und Channel.
-
Initialisierung:
new: Gibt Nullwert zurück.make: Initialisiert gemäß dem Typ der Datenstruktur.
Tipps zur Verwendung von make und new
Tipps zur Verwendung von new
Geeignet für Struct-Typen:
new wird oft verwendet, um Speicher für Structs zu reservieren und Zeiger auf diese zurückzugeben. Es ist wichtig zu beachten, dass der Anfangswert eines Struct-Zeigers der Nullwert des Structs ist.
Beispiel: Verwenden von new, um Speicher für einen Struct zu reservieren
type Person struct { Name string Age int } func main() { p := new(Person) fmt.Println(p) // Ausgabe: &{ 0} fmt.Println(p.Name) // Ausgabe: leerer String fmt.Println(p.Age) // Ausgabe: 0 }
- Von
newerstellte Zeiger: Daneweinen Zeiger auf den Struct zurückgibt, können Sie seine Felder direkt mitp.Nameoderp.Ageändern.
Tipps zur Verwendung von make
Initialisieren von Slices mit angegebener Kapazität:
make kann verwendet werden, um einen Slice mit einer angegebenen Länge und Kapazität zu initialisieren. Mit make können Sie das zugrunde liegende Array effizient reservieren und den Slice initialisieren.
Beispiel: Verwenden von make, um einen Slice mit Kapazität zu initialisieren
// Initialisiert einen Slice mit der Länge 5 und der Kapazität 10 s := make([]int, 5, 10) fmt.Println(len(s), cap(s)) // Ausgabe: 5 10
- Angeben der Map-Kapazität während der Initialisierung: Wenn Sie eine Map mit
makeerstellen, können Sie ihre anfängliche Kapazität angeben. Dies hilft, die Leistung zu optimieren, indem mehrere Speichererweiterungen beim Einfügen von Elementen vermieden werden.
Beispiel: Verwenden von make zum Initialisieren einer Map
m := make(map[string]int, 10) // Legt die anfängliche Kapazität auf 10 fest m["age"] = 30 m["height"] = 175 fmt.Println(m) // Ausgabe: map[age:30 height:175]
- Initialisieren von gepufferten Channels: Verwenden Sie
make, um einen gepufferten Channel zu erstellen und die Puffergröße des Channels anzugeben. Dies ist in der Concurrent-Programmierung sehr nützlich.
Beispiel: Verwenden von make zum Erstellen eines gepufferten Channels
ch := make(chan int, 2) ch <- 1 ch <- 2 fmt.Println(<-ch) // Ausgabe: 1
Auswählen der geeigneten Speicherreservierungsmethode
- Anwendungsszenario für Structs: Wenn Sie nur einen Zeiger auf einen Struct benötigen und keine besonderen Anforderungen während der Initialisierung haben, ist die Verwendung von
newein einfacher und üblicher Ansatz. - Anwendungsszenario für Slices, Maps und Channels: Wenn Sie einen Slice, eine Map oder einen Channel initialisieren und deren Inhalt möglicherweise ändern müssen, ist
makedie bessere Wahl – insbesondere, wenn Sie die Kapazität im Voraus angeben müssen.
Leistungsüberlegungen zu make und new
- Overhead bei der Speicherreservierung: Beim Initialisieren von Slices, Maps und Channels reserviert
makenicht nur Speicher, sondern führt auch eine Typinitialisierung durch, was zu zusätzlichem Overhead führen kann. Im Gegensatz dazu reserviertnewnur Speicher und initialisiert ihn mit dem Nullwert, sodass der Overhead relativ gering ist. - Vermeiden unnötiger Speicherreservierungen: Für Typen wie Slices, Maps oder Channels wird empfohlen, bei Verwendung von
makeeine geeignete Kapazität anzugeben, um die Anzahl der Speicherneuzuweisungen zu reduzieren.
Häufige Fehlverwendungen
- Falsche Verwendung von
newzum Erstellen von Slices oder Maps: Wennnewmit Slices, Maps oder Channels verwendet wird, gibt es nur den Nullwert des Typs zurück und führt keine Initialisierung durch. Wenn Sie alsonewverwenden, um einen Slice, eine Map oder einen Channel zu erstellen, und versuchen, direkt auf deren Inhalt zuzugreifen, führt dies zu einem Laufzeitfehler.
Falsches Beispiel: Falsche Verwendung von new zum Erstellen einer Map
m := new(map[string]int) // Falsch: gibt einen Zeiger zurück, keine initialisierte Map m["age"] = 30 // Laufzeitfehler: m ist nil
Korrekte Beispiel: Sie sollten make verwenden, um eine Map zu initialisieren.
m := make(map[string]int) m["age"] = 30
Zusammenfassung
In Go sind make und new beides Schlüsselwörter für die Speicherreservierung, und obwohl ihre Funktionen ähnlich sind, weisen sie deutliche Unterschiede auf.
new wird verwendet, um Speicher für einen Typ zu reservieren und einen Zeiger zurückzugeben, und ist für die meisten Typen geeignet;
während make hauptsächlich zum Initialisieren von Slices, Maps und Channels verwendet wird und stärkere Initialisierungsfunktionen bietet.
new: Geeignet zum Erstellen von Zeigern auf Struct-Typen und andere grundlegende Typen und initialisiert den Speicher mit dem Nullwert.make: Wird zum Initialisieren von Slices, Maps und Channels verwendet, unterstützt das Angeben der Kapazität und schließt die interne Initialisierung ab.
Das Verständnis der verschiedenen Anwendungsszenarien und Leistungsauswirkungen dieser beiden wird Ihnen helfen, effizienteren und wartbareren Go-Code zu schreiben.
We are Leapcell, your top choice for hosting Go projects.
Leapcell is the Next-Gen Serverless Platform for Web Hosting, Async Tasks, and Redis:
Multi-Language Support
- Develop with Node.js, Python, Go, or Rust.
Deploy unlimited projects for free
- pay only for usage — no requests, no charges.
Unbeatable Cost Efficiency
- Pay-as-you-go with no idle charges.
- Example: $25 supports 6.94M requests at a 60ms average response time.
Streamlined Developer Experience
- Intuitive UI for effortless setup.
- Fully automated CI/CD pipelines and GitOps integration.
- Real-time metrics and logging for actionable insights.
Effortless Scalability and High Performance
- Auto-scaling to handle high concurrency with ease.
- Zero operational overhead — just focus on building.
Explore more in the Documentation!
Follow us on X: @LeapcellHQ

