Wie man eine Struktur in Golang kopiert
Min-jun Kim
Dev Intern · Leapcell

Key Takeaways
- Flache Kopie verwendet direkte Zuweisung, funktioniert aber nicht gut für Referenztypen.
- Tiefe Kopie erfordert manuelle Zuweisung für Pointer, Slices und Maps, um unbeabsichtigte Änderungen zu vermeiden.
- JSON-Serialisierung bietet eine einfache Lösung für tiefe Kopien, hat aber Performance-Overhead.
Das Kopieren von Strukturen (Structs) in Golang ist eine häufige Anforderung, sei es zum Klonen von Daten, zum Vermeiden unbeabsichtigter Änderungen oder zur Handhabung von nebenläufigen Operationen. Dieser Artikel erklärt verschiedene Möglichkeiten, Structs in Go zu kopieren, einschließlich flacher Kopie, tiefer Kopie und Best Practices.
Flache Kopie einer Struktur
Eine flache Kopie in Go bedeutet, eine neue Struktur mit den gleichen Werten wie das Original zu erstellen. Dies funktioniert gut, wenn die Struktur nur primitive Typen oder Werte enthält, die keine Pointer beinhalten.
Verwenden der Zuweisung
Der einfachste Weg, eine Struktur zu kopieren, ist die direkte Zuweisung:
package main import "fmt" type Person struct { Name string Age int } func main() { original := Person{Name: "Alice", Age: 30} copy := original // Flache Kopie copy.Name = "Bob" // Das Ändern der Kopie wirkt sich nicht auf das Original aus fmt.Println("Original:", original) // Output: {Alice 30} fmt.Println("Copy:", copy) // Output: {Bob 30} }
Da Go Strukturvariablen als Werttypen behandelt, erstellt die direkte Zuweisung eine neue Kopie der Struktur im Speicher.
Tiefe Kopie einer Struktur
Eine tiefe Kopie stellt sicher, dass alle Felder, einschließlich Pointer und Slices, unabhängig kopiert werden, anstatt Speicherreferenzen zu teilen.
Kopieren einer Struktur mit Pointern
Wenn eine Struktur Pointer-Felder enthält, kopiert die direkte Zuweisung die Pointer-Referenz anstelle der tatsächlichen Daten. Dies kann zu unbeabsichtigten Seiteneffekten führen.
package main import "fmt" type Person struct { Name *string Age int } func deepCopy(p Person) Person { nameCopy := *p.Name // Dereferenzieren, um einen neuen String-Wert zu erstellen return Person{ Name: &nameCopy, Age: p.Age, } } func main() { name := "Alice" original := Person{Name: &name, Age: 30} copy := deepCopy(original) *copy.Name = "Bob" // Das Ändern des Namens der Kopie wirkt sich nicht auf das Original aus fmt.Println("Original:", *original.Name) // Output: Alice fmt.Println("Copy:", *copy.Name) // Output: Bob }
Hier wird eine neue String-Variable (nameCopy
) erstellt, um zu verhindern, dass die ursprüngliche Struktur geändert wird.
Kopieren einer Struktur mit Slices und Maps
Slices und Maps sind Referenztypen, was bedeutet, dass das Kopieren über die Zuweisung keine tiefe Kopie erstellt. Stattdessen sollten Sie manuell einen neuen Slice oder eine neue Map zuweisen und jedes Element kopieren.
package main import "fmt" type Person struct { Name string Scores []int } func deepCopy(p Person) Person { scoresCopy := make([]int, len(p.Scores)) copy(scoresCopy, p.Scores) // Verwenden der eingebauten Copy-Funktion return Person{ Name: p.Name, Scores: scoresCopy, } } func main() { original := Person{Name: "Alice", Scores: []int{90, 85, 88}} copy := deepCopy(original) copy.Scores[0] = 100 // Das Ändern der Kopie wirkt sich nicht auf das Original aus fmt.Println("Original Scores:", original.Scores) // Output: [90 85 88] fmt.Println("Copy Scores:", copy.Scores) // Output: [100 85 88] }
Die Funktion copy()
wird verwendet, um Slice-Elemente in einen neuen Slice zu kopieren, wodurch die Unabhängigkeit vom Original sichergestellt wird.
Kopieren von Strukturen mithilfe der JSON-Codierung
Für komplexe Strukturen ist die JSON-Serialisierung eine bequeme Möglichkeit, eine tiefe Kopie zu erreichen.
package main import ( "encoding/json" "fmt" ) type Person struct { Name string Age int Tags []string } func deepCopy(original Person) Person { var copy Person data, _ := json.Marshal(original) // Serialisieren in JSON json.Unmarshal(data, ©) // Deserialisieren in eine neue Struktur return copy } func main() { original := Person{Name: "Alice", Age: 30, Tags: []string{"engineer", "gamer"}} copy := deepCopy(original) copy.Tags[0] = "artist" // Das Ändern der Kopie wirkt sich nicht auf das Original aus fmt.Println("Original Tags:", original.Tags) // Output: [engineer gamer] fmt.Println("Copy Tags:", copy.Tags) // Output: [artist gamer] }
Die JSON-basierte Kopie ist zwar einfach, hat aber einige Nachteile:
- Performance-Overhead: Serialisierung und Deserialisierung können langsamer sein als das manuelle Kopieren.
- Typsicherheit: JSON behält keine Go-spezifischen Typen wie
interface{}
oder Funktions-Pointer bei.
Best Practices zum Kopieren von Strukturen
- Verwenden Sie die direkte Zuweisung für einfache Strukturen: Wenn eine Struktur nur Werttypen (wie
int
,float64
oderstring
) enthält, reicht die direkte Zuweisung aus. - Kopieren Sie Pointer, Slices und Maps manuell: Stellen Sie neue Zuweisungen sicher, um unbeabsichtigte Änderungen zu verhindern.
- Erwägen Sie
json.Marshal
für tiefe Kopien: Nützlich für komplexe Strukturen, kann aber Performance-Kosten verursachen. - Verwenden Sie eine Deep-Copy-Bibliothek für große Projekte: Bibliotheken wie
copier
(https://github.com/jinzhu/copier) bieten generische Lösungen für Deep Copies.
Fazit
Das Kopieren von Structs in Go hängt davon ab, ob Sie eine flache oder tiefe Kopie benötigen. Einfache Zuweisungen funktionieren für wertbasierte Strukturen, während die tiefe Kopie eine manuelle Zuweisung für Pointer-basierte und Referenztypen erfordert. Das Verständnis dieser Techniken hilft Ihnen, häufige Fehler zu vermeiden und die Datenintegrität in Go-Anwendungen sicherzustellen.
FAQs
Slices und Maps sind Referenztypen, daher kopiert die Zuweisung die Referenz, nicht die Daten.
Das manuelle Kopieren von Feldern ist am schnellsten; die JSON-Serialisierung ist einfacher, aber langsamer.
Verwenden Sie die tiefe Kopie, wenn die Struktur Zeiger, Slices oder Maps enthält, um gemeinsame Änderungen zu verhindern.
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-Sprach-Unterstützung
- Entwickeln Sie mit Node.js, Python, Go oder Rust.
Stellen Sie unbegrenzt 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.
- Vollständig automatisierte CI/CD-Pipelines und GitOps-Integration.
- Echtzeitmetriken und -protokollierung für verwertbare Erkenntnisse.
Mühelose Skalierbarkeit und hohe Leistung
- Automatische Skalierung zur einfachen Bewältigung hoher Parallelität.
- Kein Betriebsaufwand – konzentrieren Sie sich einfach auf das Bauen.
Erfahren Sie mehr in der Dokumentation!
Folgen Sie uns auf X: @LeapcellHQ