ホームページ >バックエンド開発 >Golang >Go 構造体のスライスに追加するためにポインター レシーバーが必要なのはなぜですか?

Go 構造体のスライスに追加するためにポインター レシーバーが必要なのはなぜですか?

Mary-Kate Olsen
Mary-Kate Olsenオリジナル
2024-12-27 17:39:12259ブラウズ

Why Do I Need a Pointer Receiver to Append to a Slice in a Go Struct?

Go 構造体のスライス プロパティへの追加

Go 構造体内のスライス プロパティに値を追加しようとすると、予期しない動作が発生する可能性があります特定の呼び出し順序に従っていない場合。この記事では、この問題の背後にある理由を調査し、解決策を提供します。

提供されたコード例では、問題を示すために、異なる構造体型内で 3 つのメソッドが定義されています。 Test1 と Test2 は、 run() メソッドがスライス プロパティを直接操作するため、期待どおりに動作します。ただし、Test3 では、combo() メソッドは、ポインター レシーバーではなく値レシーバーを使用して run() から呼び出されます。

ポインター レシーバーが必要な理由

Go では、すべての値は値によって渡されます。つまり、関数またはメソッドを呼び出すときに、渡された値のコピーが作成されます。 Test3 の場合、combo() が呼び出されたときに Test3 値のコピーが作成され、このコピー内のスライス プロパティへの変更は元の Test3 構造体には反映されません。

ポインター レシーバーを使用することによりfunc (c *Test3) combo() など、元の Test3 構造体が直接変更され、コピーローカルの問題が排除されます。

解決策

解決策は、 combo() メソッドのレシーバーの種類をポインタ レシーバーに変更することです。これにより、元の Test3 構造体がメソッドによって変更されていることを確認します。

更新されたコード

package main

import (
  "fmt"
)

type Test1 struct {
  all []int
}

func (c Test1) run() []int {
  for i := 0; i < 2; i++ {
    c.all = append(c.all, i)
  }
  return c.all
}

var gloabl_all []int

type Test2 struct {}

func (c Test2) run() []int {
  c.combo()
  return gloabl_all
}

func (c Test2) combo() {
  for i := 0; i < 2; i++ {
    gloabl_all = append(gloabl_all, i)
  }
}

type Test3 struct {
  all []int
}

func (c Test3) run() []int {
  c.combo()
  return c.all
}

func (c *Test3) combo() {
  for i := 0; i < 2; i++ {
    c.all = append(c.all, i)
    fmt.Println("Test3 step", i + 1, c.all)
  }
}

func main() {
  test1 := &Test1{}
  fmt.Println("Test1 final:", test1.run())

  test2 := &Test2{}
  fmt.Println("Test2 final:", test2.run())

  test3 := &Test3{}
  fmt.Println("Test3 final:", test3.run())
}

出力

Test1 final: [0 1]
Test2 final: [0 1]
Test3 step 1 [0]
Test3 step 2 [0 1]
Test3 final: [0 1]

以上がGo 構造体のスライスに追加するためにポインター レシーバーが必要なのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。