Golang のポインター レシーバーとインターフェイス実装
Go では、レシーバー関数を使用してメソッドが特定の型を操作できるようにします。メソッドにポインター レシーバーがある場合、構造体の実際のインスタンスを変更できます。
問題の理解
次のコード スニペットを検討してください:
type IFace interface { SetSomeField(newValue string) GetSomeField() string } type Implementation struct { someField string } // Method with non-pointer receiver func (i Implementation) GetSomeField() string { return i.someField } // Method with non-pointer receiver func (i Implementation) SetSomeField(newValue string) { i.someField = newValue }
このコードでは、両方のメソッドに非ポインター レシーバーがあります。これは、SetSomeField を呼び出すと、構造体のコピーが作成され、そのコピーが変更されることを意味します。元のインスタンスは変更されません。
ポインタ レシーバの使用
実際のインスタンスを変更するには、SetSomeField メソッドにポインタ レシーバが必要です:
// Method with pointer receiver func (i *Implementation) SetSomeField(newValue string) { i.someField = newValue }
SetSomeField は元のインスタンスを変更できるようになりました。ただし、これにより IFace インターフェイスを実装するときに問題が発生します。
package main import ( "fmt" ) type IFace interface { SetSomeField(newValue string) GetSomeField() string } type Implementation struct { someField string } // Method with pointer receiver func (i *Implementation) GetSomeField() string { return i.someField } // Method with pointer receiver func (i *Implementation) SetSomeField(newValue string) { i.someField = newValue } func Create() IFace { obj := Implementation{someField: "Hello"} return obj // Offending line } func main() { a := Create() // Assigning an Implementation value to an IFace variable a.SetSomeField("World") // Will panic because a is an Implementation value, not a pointer fmt.Println(a.GetSomeField()) }
Create は実装値へのポインターではなく実装値を返すため、このコードをコンパイルするとパニックが発生します。ポインター レシーバーを使用してインターフェイスを実装するには、メソッドをポインター レシーバーとして宣言し、Create 関数が実装へのポインターを返す必要があります。
type IFace interface { SetSomeField(newValue string) GetSomeField() string } type Implementation struct { someField string } // Method with pointer receiver func (i *Implementation) GetSomeField() string { return i.someField } // Method with pointer receiver func (i *Implementation) SetSomeField(newValue string) { i.someField = newValue } func Create() *Implementation { obj := Implementation{someField: "Hello"} return &obj } func main() { var a IFace a = Create() // Now assigning a pointer to Implementation to an IFace variable a.SetSomeField("World") fmt.Println(a.GetSomeField()) }
ここで、 a は実装値へのポインターです。ポインタ レシーバを備えた IFace を実装します。 SetSomeField を通じて行われた変更は、元のインスタンスに影響します。
以上がGo インターフェイス実装でポインター レシーバーを使用するとポインターを返す必要があるのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。