Go では、ポインタ レシーバを使用したメソッドは、操作する変数の元の値を保持することが知られています。の上。ただし、メソッドがポインター引数を予期しているのに、ポインター以外の値が渡された場合、明らかな矛盾があるようです。
Go ツアーの演習 51 の以下のスニペットを考えてみましょう。
func (v *Vertex) Scale(f float64) { v.X *= f v.Y *= f } func main() { v := &Vertex{3, 4} v.Scale(2) fmt.Println(v) // Output: &{6 8} }
説明によると、Scale メソッドは Vertex ではなく Vertex (*Vertex) へのポインタを受け取るため、v を変更すべきではありません。
ただし、main で v := &Vertex{3, 4} 行を v := Vertex{3, 4} に変更すると、出力は &{6 8} から {6 8 に変わります。 } (& が欠落していることに注意してください)。これは、v が非ポインター値として渡されたにもかかわらず、変更されたことを示します。
鍵は、Go の厳密に型指定された性質とコンパイラーの最適化にあります。 Scale メソッドはポインター レシーバーを想定していますが、Go は暗黙的にポインターに変換するため、ポインター以外の値も受け入れることができます。
具体的には、コンパイラーは次のコードを書き換えます。
v := Vertex{3, 4} v.Scale(2)
to:
(&v).Scale(2)
これは、メソッドが実際に v へのポインターを使用して呼び出されることを意味します。元の値を変更します。
次の Go 固有のルールは、この動作を説明します。
x (の型) のメソッド セットに m が含まれており、引数リストを m のパラメータ リストに割り当てることができます。 x がアドレス指定可能で、&x のメソッド セットに m が含まれている場合、x.m() は (&x).m() の短縮形です。
要約すると、コンパイラーが自動的に変換するため、ポインター レシーバーを持つメソッドでも非ポインター変数を変更できます。メソッドの型の安全性を維持するためのポインターへのそれら。
以上がポインター レシーバーを使用した Go メソッドがポインター以外の引数を変更するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。