Go で構文の混乱を呼び出すレシーバー メソッド
レシーバーのポインタと値の違いを調べるとき、値メソッドは次のようにできることに注意してください。ポインタ メソッドはポインタと値の両方で呼び出されますが、ポインタ メソッドはポインタのみに制限されます。この制限は、ポインター メソッドがレシーバーを変更できることに由来しており、値のコピーに対して呼び出された場合、変更は破棄されます。
ただし、値に対して呼び出されるポインター メソッドを示すコード例は混乱を引き起こします。コードは次のとおりです。
<code class="go">package main import ( "fmt" "reflect" ) type age int func (a age) String() string { return fmt.Sprintf("%d year(s) old", int(a)) } func (a *age) Set(newAge int) { if newAge >= 0 { *a = age(newAge) } } func main() { var vAge age = 5 pAge := new(age) fmt.Printf("Type information:\n\tvAge: %v\n\tpAge: %v\n", reflect.TypeOf(vAge), reflect.TypeOf(pAge)) fmt.Printf("vAge.String(): %v\n", vAge.String()) fmt.Printf("vAge.Set(10)\n") vAge.Set(10) fmt.Printf("vAge.String(): %v\n", vAge.String()) fmt.Printf("pAge.String(): %v\n", pAge.String()) fmt.Printf("pAge.Set(10)\n") pAge.Set(10) fmt.Printf("pAge.String(): %v\n", pAge.String()) }</code>
ドキュメントでは不可能であると記載されていますが、このコードはエラーなしでコンパイルおよび実行されます。では、この明らかな矛盾の原因は何でしょうか?
その答えは、アドレス指定可能な値の概念の中にあります。 Go 仕様では、「x (の型) のメソッド セットに m が含まれており、引数リストを m のパラメータ リストに割り当てることができる場合、メソッド呼び出し x.m() は有効です。」と定義されています。さらに、「x がアドレス可能で、&x のメソッド セットに m が含まれている場合、x.m() は (&x).m() の短縮形です。」
この場合、vAge はアドレス可能であり、有効なメモリ アドレスがあることを意味します。 。 vAge.Set() を呼び出すと、コンパイラーは、値のアドレスを使用してポインター レシーバー メソッド Set() を呼び出すこともできることを認識します。これは (&vAge).Set() と同等です。
以上が## Go で値のポインター メソッドを呼び出すことができるのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。