Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Pointers 关于接口分配_Pointers_Go_Methods_Interface - Fatal编程技术网

Pointers 关于接口分配

Pointers 关于接口分配,pointers,go,methods,interface,Pointers,Go,Methods,Interface,当一个结构指针被分配给一个接口时,为什么Go不认为这是类型不匹配错误呢 主程序包 输入“fmt” 类型ABC接口{ 一个()字符串 b()int } 类型XYZ结构{ aa字符串 bb int } func(xyz xyz)a()字符串{ 返回“XYZ” } func(xyz xyz)b()int{ 返回123 } func main(){ 变量xyz*xyz var abc abc=xyz//abc的类型是*main.xyz,我认为Golang可以在这里找到这个错误,但为什么不呢? fmt.P

当一个结构指针被分配给一个接口时,为什么Go不认为这是类型不匹配错误呢

主程序包
输入“fmt”
类型ABC接口{
一个()字符串
b()int
}
类型XYZ结构{
aa字符串
bb int
}
func(xyz xyz)a()字符串{
返回“XYZ”
}
func(xyz xyz)b()int{
返回123
}
func main(){
变量xyz*xyz
var abc abc=xyz//abc的类型是*main.xyz,我认为Golang可以在这里找到这个错误,但为什么不呢?
fmt.Printf(“%T\n”,abc)
a、 ret:=abc。(*XYZ)
fmt.Println(a,ret)//a的类型是*main.XYZ
fmt.Println(a.a())//将发生错误,因为a(*main.XYZ)的类型未实现接口ABC
}
我想知道为什么Go不认为这是“var abc=xyz”的错误

将发生错误,因为(*main.XYZ)的类型未实现接口ABC

*main.XYZ
实现
ABC
(否则
ABC=XYZ
将在编译时失败,例如尝试将方法
b
重命名为
c
),但变量
a
持有一个
nil
指针(类型
*XYZ
)。由于
XYZ.a()
方法具有值接收器,因此要调用它,必须取消引用
*XYZ
类型的指针值。但是
nil
指针不指向任何东西,它不能被取消引用,尝试这样做会导致运行时恐慌,正如您所经历的那样

如果您在开始时使用非
nil
指针初始化
xyz
,它将工作:

var xyz *XYZ = new(XYZ)
试穿一下

还要注意,如果
XYZ.a()
XYZ.b()
将有指针接收器,那么如果
XYZ
nil
,它也会工作:

func (xyz *XYZ) a() string {
    return "XYZ"
}

func (xyz *XYZ) b() int {
    return 123
}

func main() {
    var xyz *XYZ
    // ...

试穿一下。这样做的原因是,如果接收器是指针,则不必为了使用指针接收器调用方法而取消对
nil
指针的引用,因此不会发生运行时死机。当然,如果您在方法中引用
XZY.aa
XYZ.bb
字段,那将是一种运行时恐慌,但您当前的方法实现没有这样做,因此它可以工作。

类型可能有与其关联的方法集。接口类型的方法集是其接口。任何其他类型T的方法集由使用接收器类型T声明的所有方法组成。相应指针类型*T的方法集是使用接收器*T或T声明的所有方法集(即,它还包含方法集T)

:

接口类型指定称为其接口的方法集。接口类型的变量可以使用作为接口的任何超集的方法集存储任何类型的值。这种类型被称为实现接口

调用
*XYZ.a()
时,Go编译器始终可以自动取消对指针的引用以获取值接收器。这样做没有坏处,因为接收方不能被修改(就调用方而言)

当且仅当该值可寻址时,反向为真:

类型T结构{}
func(*T)M()
func main(){
变量t
t、 M()//确定;t是可寻址的,编译器将其重写为(*t).M()
变量m映射[string]T
m[“x”].m()//错误:无法获取m[“x”]的地址
}

另请参见:

@icza,也许我不完全理解你所说的,但我想我现在可以回答这个问题了。当我对一个值调用一个方法时(不是指针,是实现接口的结构的方法,方法的接收者是指针)。Golang将创建一个新对象并从原始结构值复制值,然后iface.data将指向新对象,现在,当我们将新对象的指针传递给方法时,它将被修改,但此操作不会更改原始结构值,这没有任何用处,因此,当我们为接口(指针接收器)分配一个结构值时,Golang将发生一个错误。

XYZ很好地实现了接口ABC,所以我想你可能误解了接口的工作原理?如果一个结构拥有接口指定的所有方法,那么它将实现它,而无需对此做任何事情。这就是你所做的,XYZ有ABC指定的所有方法,即
a()string
b()int
。谢谢,我定义了a()和b()的接收者是XYZ,不是*XYZ。XYZ.a()正常,*XYZ.a()将无法工作。因此,我认为*XYZ没有实现ABC。谢谢,Golang可以在指向nil值的指针上调用方法a()(但类型不同,XYZ),它将nil作为接收方传递给a()。所以,Go应该知道*XYZ不是a()的接收者,它可以确定a()不能在*XYZ上调用。当然,我也像你一样尝试过,在我提问之前,只需修改(XYZ XYZ)a()=>(XYZ*XYZ)a(),它就可以正常工作,因为接收者是匹配的。我在想:既然Golang允许这种情况,为什么在我将*XYZ分配给abc时不会出现错误?@JoeRadar这与匹配无关。如果方法具有非指针接收器,则
XYZ
*XYZ
类型都实现该接口。问题是
nil
指针不能被取消引用以调用非指针方法。如果指针被初始化,它也可以与非指针方法一起工作。答案都写在上面了。也许你说的我都懂了,但我想我可以回答这个问题。当我调用一个结构的方法时