Go インターフェイス実装のレシーバー タイプを理解する
Go では、メソッドはいずれかの値レシーバー (func (t T) m()) を持つことができます。または、構造体型のポインター レシーバー (func (t *T) m())。レシーバーのタイプによって、メソッドを呼び出すときに使用する値が決まります。
次のコードを考えてみましょう:
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 }
なぜ変数 t1 のいずれかを使用して TourGuide のメソッドを呼び出すことができるのか不思議に思うかもしれません。 TourGuide 型のポインタ、または *tourGuide 型のポインタ t2 ですが、t1 を型のインターフェイス変数 g1 に割り当てることはできませんgreeter.
その理由は、インターフェイス メソッドの受信側の型にあります。この場合、hello と Goodbye の両方にポインタ レシーバがあります。そのため、レシーバー値として使用できるのはポインター値のみです。
t1.hello() および t1.goodbye() を呼び出すと、コンパイラーは自動的に t1 のアドレスを取得し、それをレシーバーとして使用します。 t1 はアドレス指定可能な値であるためです。
ただし、t1 を g1 に代入しようとすると、コンパイラは t1 がアドレス可能な値ではないことを認識します。ポインタ値ですが、tourGuide 型の値です。インターフェイスはアドレス指定できないため、コンパイラは t1 のアドレスを取得して g1 に割り当てることができません。
要約すると、ポインタ レシーバはメソッドを呼び出すためにポインタ値を必要としますが、値レシーバはいずれかの値で呼び出すことができます。またはポインタ。ポインター レシーバー メソッドを使用してインターフェイスを実装する場合、インターフェイスに割り当てることができるのはポインター値のみです。
以上がGo でポインター レシーバー メソッドを使用してインターフェイスに値レシーバーを割り当てることができないのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。