Effective Go の「ポインターと値」セクションでは、「値メソッドはポインターと値で呼び出すことができる」と記載されています。ただし、ポインタ メソッドはポインタに対してのみ呼び出すことができます。」これは、ポインタ メソッドがレシーバを変更する可能性があり、値のコピーに対してポインタ メソッドを呼び出すと、これらの変更が破棄されてしまうためです。
しかし、一部の開発者は、それらを実行できる状況に遭遇しました。値に対してポインター メソッドを呼び出しますが、これは文書化された構文規則に矛盾しているように見えます。この混乱を明確にするために、この動作をさらに詳しく調べます。
次の Go コードを考えてみましょう。
<code class="go">package main import ( "fmt" "reflect" ) type age int func (a age) String() string { return fmt.Sprintf("%d yeasr(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("TypeOf =>\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>
この例では、2 つのメソッドを使用して age タイプを定義します。 String( ) (値メソッド) と Set() (ポインター メソッド)。このコードは、2 つの変数を作成します。vAge (age 型の値)、および pAge (年齢値へのポインター) です。
ドキュメントでは、vAge.Set() が有効な構文ではないことが示されているにもかかわらず、コードは次の構文を使用せずにコンパイルされます。エラー。これは、vAge がアドレス可能である、つまり参照できるメモリ アドレスがあるためです。言語仕様に従って、アドレス指定可能な変数 x に対するメソッド呼び出し x.m() は、x のメソッド セットに m が含まれている場合に有効です。
この場合、vAge はアドレス指定可能であり、*age のメソッド セットには Set が含まれているため、 () の呼び出し vAge.Set() は (&vAge).Set() の短縮表記です。基本的に、&演算子は、vAge へのポインターを取得するために暗黙的に使用されています。
したがって、このコードは、アドレス指定可能な値に対する値メソッドの呼び出しは、その値へのポインターに対するメソッドの呼び出しと同等であるため、実際にポインターに対して値メソッドを呼び出すことができることを示しています。価値。ポインタ メソッド Set() は依然としてポインタに対してのみ呼び出すことができますが、値がアドレス指定可能な場合は、暗黙的な逆参照により構文 vAge.Set() が有効になります。
以上が## Go で値のポインター メソッドを呼び出すことができるのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。