次の Go コード例を考えます。
package main import "fmt" type greeter interface { hello() goodbye() } type tourGuide struct { name string } func (t tourGuide) hello() { fmt.Println("Hello", t.name) } func (t *tourGuide) goodbye() { fmt.Println("Goodbye", t.name) } func main() { var t1 tourGuide = tourGuide{"James"} t1.hello() // Hello James t1.goodbye() // Goodbye James (same as (&t1).goodbye()) var t2 *tourGuide = &tourGuide{"Smith"} t2.hello() // Hello Smith t2.goodbye() // Goodbye Smith (same as (*t2).hello()) // illegal: t1 is not assignable to g1 (why?) // var g1 greeter = t1 var g2 greeter = t2 g2.hello() // Hello Smith g2.goodbye() // Goodbye Smith }
上記のコードでは、次のことができます。 TourGuide (t1) 型の変数または TourGuide へのポインタを使用して、構造体 TourGuide の 2 つのメソッドを呼び出します。 (t2)。ただし、インターフェイスを実装すると状況が変わります。グリーター インターフェイス タイプの変数は、tourGuide へのポインターから割り当てることができますが、tourGuide 値からは割り当てることができません。なぜそうなるのですか?
その理由を理解するには、レシーバーのタイプと値のセマンティクスの概念を理解することが重要です。 Go のメソッドには、値レシーバーまたはポインタ レシーバーのいずれかを含めることができます。値レシーバー メソッドは値のコピーに対して呼び出されますが、ポインター レシーバー メソッドは元の値に対して呼び出されます。
値がコピーされると、元の値の新しい独立したコピーが作成されます。コピーに変更を加えても、元の値には影響しません。これは値セマンティクスとして知られています。
tourGuide の例では、hello メソッドには値レシーバーがあり、goodbye メソッドにはポインター レシーバーがあります。 t1.hello() を呼び出すと、t1 のコピーが作成され、そのコピー上で hello メソッドが呼び出されます。 t1.goodbye() を呼び出すと、元の t1 値に対して Goodbye メソッドが呼び出されます。
Go のインターフェースは値セマンティクスによって実装されます。これは、値がインターフェイスに割り当てられると、その値のコピーが作成されることを意味します。ポインタ レシーバ メソッドの場合、これは値のコピーにアドレスがないことを意味し、そのためメソッドを呼び出すことができません。
たとえば、t1 を g1 に代入すると (これははインターフェイス値です)。次のコード行では、
// illegal: t1 is not assignable to g1 (why?) // var g1 greeter = t1
t1 のコピーが作成され、そのコピーに hello メソッドと Goodbye メソッドが実装されます。ただし、コピーにはアドレスがないため、コピーに対して Goodbye メソッドを呼び出すことはできません。
対照的に、次のコード行で t2 を g2 に代入すると、
var g2 greeter = t2
t2 (tourGuide へのポインタ) のコピーが作成され、ポインタのコピーに hello メソッドと Goodbye メソッドが実装されます。この場合、ポインタのコピーにはアドレスがあるため、そのコピーに対して Goodbye メソッドを呼び出すことができます。
要約すると、グリーター インターフェイス型の変数が代入可能である理由TourGuide へのポインターからではなく、tourGuide 値からではないのは、インターフェイスが値セマンティクスによって実装されているためです。値がインターフェイスに割り当てられると、値のコピーが作成されます。インターフェイスのメソッドにポインター レシーバーがある場合、コピーにはアドレスがないため、コピー上でメソッドを呼び出すことはできません。
以上がGo の「greeter」インターフェイスには「tourGuide」値を割り当てることができないのに、「tourGuide」へのポインタを割り当てることはできるのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。