Pointers 满足接口的Go-struct方法的类型
给出以下Go代码示例:Pointers 满足接口的Go-struct方法的类型,pointers,go,methods,struct,interface,Pointers,Go,Methods,Struct,Interface,给出以下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(
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
}
我可以使用tourGuidet1
类型的变量或指向tourGuidet2
的指针来调用structtourGuide
的两个方法。换句话说,我可以使用T
或*T
类型的变量调用带有T
接收器的方法。类似地,我可以使用类型为T
(如果T
是)或*T
的变量调用带有*T
接收器的方法。我知道编译器在这里处理差异(请参阅代码中的注释)
然而,当我们实现接口时,情况会发生变化。在上述代码中,greeter
接口类型的变量可从指向tourGuide
的指针分配,但不能从tourGuide
分配
谁能告诉我为什么会这样?为什么我能够调用
t1.hello()
和t1.bye()
,但是对于接口greeter
,t1
来说,不知为什么t1
还不够?如果一个方法有一个指针接收器,那么只有一个指针值可以用作接收器值。因此,要对某个值调用此方法,该值本身必须是指针,或者必须能够获取其地址(用作接收器)
例如,如果您有一个变量,它是,因此可以获取它的地址并将其用作接收器。规范允许你这样做,这是自动发生的
包装在接口中的值不可寻址。创建接口值时,将复制包装在接口中的值。因此,无法确定其地址。从理论上讲,您可以允许获取副本的地址,但这将导致(甚至)比它提供的好处更大的混乱,因为地址将指向副本,而带有指针接收器的方法只能修改副本,而不能修改原件
请参阅此答案,其中详细说明/证明在创建接口值时复制了值:如果您有指向结构的指针,则go将允许您访问结构及其函数上的属性,这些属性具有值类型接收器(与指针接收器类似),而无需取消引用指针,但这只适用于一个级别的指针,请参见下面的代码,我将t2转换为指向
旅游指南
的指针,此时我需要显式取消引用它,使其返回到指向旅游指南
的指针。将指向结构的指针的第一级视为一种特殊情况,go允许您使用Syntactic sugar访问值类型属性和函数,从而避免您必须不断手动取消引用变量
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 tmpT2 *tourGuide = &tourGuide{"Smith"}
var t2 **tourGuide = &tmpT2
(*t2).hello() // Hello Smith
(*t2).goodbye() // Goodbye Smith (same as (*t2).hello())
//illegal: t1 is not assignable to g1 (why?)
//var g1 greeter = t1
//now this is illegal too
//var g2 greeter = t2
var g3 greeter = (*t2)
g3.hello() // Hello Smith
g3.goodbye() // Goodbye Smith
}
解释为什么Go阻止您获取存储在接口中的值的地址
tl;dr这是因为当不同类型的值B随后存储在接口中时,指向接口中a类型值的a指针将无效。可能重复的感谢。但我的问题是,为什么编译器允许使用值类型和指针调用具有值和指针接收器的结构方法。但是没有为接口提供类似的支持吗?与其说语言是如何工作的,不如说它更像是一个设计问题?@danze如果这是一个设计问题,那么它就不适合这样做。@Volker我的问题源于不完全理解Go接口,而公认的答案对我来说澄清了这一点。这不是设计问题,这是我想要的。现在我明白了编译器为什么会这样做了。谢谢向上投票,因为你链接的答案(也是你写的)非常好。不过,我认为这应该被改写为“我的答案在这里”,以表明另一个答案也是你写的。