Golangでの構造体をコピーする方法
Min-jun Kim
Dev Intern · Leapcell

Key Takeaways
- シャローコピーは直接代入を使用 しますが、参照型には適していません。
- ディープコピーには手動での割り当てが必要 で、ポインタ、スライス、およびマップの意図しない変更を避けるためです。
- JSONシリアライゼーションは簡単なディープコピーソリューションを提供 しますが、パフォーマンスのオーバーヘッドがあります。
Golangで構造体をコピーすることは、データの複製、意図しない変更の回避、または並行処理の処理など、一般的な要件です。この記事では、Goで構造体をコピーするさまざまな方法について、シャローコピー、ディープコピー、およびベストプラクティスを含めて説明します。
構造体のシャローコピー
Goでのシャローコピーとは、元の構造体と同じ値を持つ新しい構造体を作成することを意味します。これは、構造体がプリミティブ型またはポインタを含まない値のみを含む場合に適しています。
代入の使用
構造体をコピーする最も簡単な方法は、直接代入を使用することです。
package main import "fmt" type Person struct { Name string Age int } func main() { original := Person{Name: "Alice", Age: 30} copy := original // シャローコピー copy.Name = "Bob" // コピーの変更は元の構造体に影響を与えません fmt.Println("Original:", original) // 出力: {Alice 30} fmt.Println("Copy:", copy) // 出力: {Bob 30} }
Goは構造体変数を値型として扱うため、直接代入はメモリ内に構造体の新しいコピーを作成します。
構造体のディープコピー
ディープコピーは、ポインタやスライスを含むすべてのフィールドが、メモリ参照を共有するのではなく、独立してコピーされることを保証します。
ポインタを持つ構造体のコピー
構造体にポインタフィールドが含まれている場合、直接代入は実際のデータではなくポインタ参照をコピーします。これにより、意図しない副作用が発生する可能性があります。
package main import "fmt" type Person struct { Name *string Age int } func deepCopy(p Person) Person { nameCopy := *p.Name // 新しい文字列値を作成するためにデリファレンス return Person{ Name: &nameCopy, Age: p.Age, } } func main() { name := "Alice" original := Person{Name: &name, Age: 30} copy := deepCopy(original) *copy.Name = "Bob" // コピーのNameの変更は元の構造体に影響を与えません fmt.Println("Original:", *original.Name) // 出力: Alice fmt.Println("Copy:", *copy.Name) // 出力: Bob }
ここでは、元の構造体の変更を防ぐために、新しい文字列変数(nameCopy
)が作成されます。
スライスとマップを持つ構造体のコピー
スライスとマップは参照型であり、代入によるコピーはディープコピーを作成しません。代わりに、新しいスライスまたはマップを手動で割り当て、各要素をコピーする必要があります。
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) // 組み込みのcopy関数を使用 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 // コピーの変更は元の構造体に影響を与えません fmt.Println("Original Scores:", original.Scores) // 出力: [90 85 88] fmt.Println("Copy Scores:", copy.Scores) // 出力: [100 85 88] }
copy()
関数は、スライス要素を新しいスライスにコピーするために使用され、元からの独立性を保証します。
JSONエンコーディングを使用した構造体のコピー
複雑な構造体の場合、JSONシリアライゼーションはディープコピーを実現するのに便利な方法です。
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) // JSONにシリアライズ json.Unmarshal(data, ©) // 新しい構造体にデシリアライズ return copy } func main() { original := Person{Name: "Alice", Age: 30, Tags: []string{"engineer", "gamer"}} copy := deepCopy(original) copy.Tags[0] = "artist" // コピーの変更は元に影響を与えません fmt.Println("Original Tags:", original.Tags) // 出力: [engineer gamer] fmt.Println("Copy Tags:", copy.Tags) // 出力: [artist gamer] }
JSONベースのコピーは簡単ですが、いくつかの欠点があります。
- パフォーマンスのオーバーヘッド: シリアライゼーションとデシリアライゼーションは、手動コピーよりも遅くなる可能性があります。
- 型安全性: JSONは、
interface{}
や関数ポインタなどのGo固有の型を保持しません。
構造体をコピーするためのベストプラクティス
- 単純な構造体には直接代入を使用: 構造体が値型(
int
、float64
、またはstring
など)のみを含む場合は、直接代入で十分です。 - ポインタ、スライス、およびマップを手動でコピー: 意図しない変更を防ぐために、新しい割り当てを確保します。
- ディープコピーには
json.Marshal
を検討: 複雑な構造体に役立ちますが、パフォーマンスコストが発生する可能性があります。 - 大規模プロジェクトにはディープコピーライブラリを使用:
copier
(https://github.com/jinzhu/copier) などのライブラリは、ディープコピーのための一般的なソリューションを提供します。
結論
Goで構造体をコピーするかどうかは、シャローコピーが必要かディープコピーが必要かによって異なります。単純な代入は値ベースの構造体で機能し、ディープコピーはポインタベースおよび参照型の手動割り当てが必要です。これらのテクニックを理解することで、一般的な落とし穴を回避し、Goアプリケーションのデータ整合性を確保できます。
FAQs
スライスとマップは参照型であるため、代入はデータではなく参照をコピーします。
フィールドを手動でコピーするのが最速です。JSONシリアライゼーションは簡単ですが、より遅いです。
共有の変更を防ぐために、構造体にポインタ、スライス、またはマップが含まれている場合は、ディープコピーを使用します。
Leapcellは、Goプロジェクトをホストするための最適な選択肢です。
Leapcellは、Webホスティング、非同期タスク、およびRedis向けの次世代サーバーレスプラットフォームです。
多言語サポート
- Node.js、Python、Go、またはRustで開発します。
無制限のプロジェクトを無料でデプロイ
- 使用量に対してのみ支払い - リクエストや料金は発生しません。
比類のないコスト効率
- アイドル料金なしの従量課金。
- 例:25ドルで、平均応答時間60msで694万リクエストをサポートします。
合理化された開発者エクスペリエンス
- 簡単なセットアップのための直感的なUI。
- 完全に自動化されたCI/CDパイプラインとGitOps統合。
- 実用的な洞察のためのリアルタイムメトリックとロギング。
簡単なスケーラビリティと高性能
- 簡単な同時実行を処理するための自動スケーリング。
- 運用オーバーヘッドゼロ - 構築に集中するだけです。
詳細については、ドキュメントをご覧ください。
Xでフォローしてください:@LeapcellHQ