给出以下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使用tourGuide类型的变量t1或指向tourGuide的指针来调用结构的两个方法t2。换句话说,我可以T使用类型为T或的变量来使用Receiver 调用方法*T。类似地,我可以调用一个方法*T使用类型的变量接收机T(如果T是可寻址的)或*T。我了解编译器会在此处处理这些差异(请参见代码中的注释)。
tourGuide
t1
t2
T
*T
但是,当我们实现接口时,情况会发生变化。在上面的代码中,类型为greeterinterface 的变量可以从指针分配,tourGuide但不能从指针分配tourGuide。
greeter
谁能告诉我为什么会这样吗?为什么我可以打电话t1.hello(),t1.goodbye()但t1对于接口来说却是不足够的greeter?
t1.hello()
t1.goodbye()
如果方法具有指针接收器,则只能将指针值用作接收器值。因此,要在某个值上调用此方法,该值本身必须是一个指针,或者必须有可能获取其地址(用作接收方)。
例如,如果您有一个变量,则该变量是可寻址的,因此可以获取其地址并将其用作接收器。规范允许您执行此操作,这会自动发生。
包装在接口中的值是不可寻址的。创建接口值时,将复制包装在接口中的值。因此,无法使用其地址。从理论上讲,您可以允许获取副本的地址,但这将带来(甚至)比提供的好处更多的混乱,因为该地址将指向副本,并且带有指针接收器的方法只能修改副本而不是原始的。