常见结构体赋值给接口出现的错误
package main import "fmt" type Animal interface { Eat() Move() } type Human struct { } func (h *Human)Eat() { fmt.Println("Eat") } func (h Human)Move() { fmt.Println("Move") } func main() { var animal1 Animal animal1 = &Human{} animal1.Move() animal1.Eat() //这样却能调用 h := Human{} h.Eat() h.Move() //这样却语法错误 /** var animal Animal animal = Human{} animal.Move() animal.Eat() //cannot use Human{…} (value of type Human) as type Animal in assignment: //Human does not implement Animal (Eat method has pointer receiver) */ }
初学Go语言可能会比较迷惑,方法接受者可以是结构体或者结构体指针,接口变量可以赋值为结构体或者结构体指针。但是当遇到上面程序:animal赋值为结构体变量,Eat方法接收者为结构体指针,竟然编译错误,提示结构体Human没有实现接口Animal的方法,并且说明Eat方法接受者为结构体指针。而animal1变量赋值为结构体指针,却既能调用Eat方法,也能调用Move方法。为什么呢?
其实我们在定义了结构体Human后,Go语言不止定义了type."".Human一种类型,还定义了结构体指针类型,我们通过通过"go tool compile"看一下:
//结构体(指针)类型变量赋值给接口类型变量,自动创建对应itab类型 go.itab.*"".Human,"".Animal type.*"".Human SRODATA rel 72+4 t=5 type..namedata.Eat.+0 //方法1 rel 76+4 t=26 type.func()+0 rel 80+4 t=26 "".(*Human).Eat+0 rel 84+4 t=26 "".(*Human).Eat+0 rel 88+4 t=5 type..namedata.Move.+0 //方法2 rel 92+4 t=26 type.func()+0 rel 96+4 t=26 "".(*Human).Move+0 rel 100+4 t=26 "".(*Human).Move+0 type."".Human SRODATA rel 96+4 t=5 type..namedata.Move.+0 //方法1 rel 100+4 t=26 type.func()+0 rel 104+4 t=26 "".(*Human).Move+0 rel 108+4 t=26 "".Human.Move+0
这下明确了,结构体Human类型只有Move方法,而结构体Human指针类型有Eat以及Move方法;所以在向接口Animal类型赋值时,结构体变量无法编译通过。然而我们又发现,结构体变量h,却可以调用Eat以及Move方法,不是说结构体Human类型只有Move方法吗?其实这是编译阶段做了处理,将变量h的地址(也就是结构体Human指针类型)作为参数传递给Eat方法了。
这一点要特别注意,方法接收者不管是结构体还是结构体指针,通过结构体变量或者结构体指针变量调用,都是没有问题的。但是,一旦赋值给接口类型变量,编译时会做类型检查,发现结构体类型没有实现某些方法,可是会导致语法错误的。
再扩展思考一下为什么要这么设计呢?结构体变量赋值给接口类型变量,不是一样可以获取到该结构体地址呢?不同样可以调用Eat方法。为什么不设计成这样呢?原因其实上面已经解释过了,animal = Human{}方式赋值时,会将原始结构体变量拷贝一份副本,iface.data指向的是该副本数据,这时候获取到的地址,还是原始结构体变量的地址吗?
空接口常见错误
package main import "fmt" func main() { var a map[string]int = nil fmt.Println(a == nil) //true test(a) } func test(v interface{}) { fmt.Println(v == nil) //false }
由于任何类型都能转化为interface{},nil转化之后还等于nil吗?刚开始写Go语言,老是搞不清楚,明明最初值是nil,作为interface{}类型传递到函数之后,再判断竟然不等于nil了!现在知道了,空接口interface{}对应的变量用eface表示,肯定是不会等于nil的。
- 本文固定链接: https://www.phpmianshi.com/?id=380
- 转载请注明: admin 于 PHP面试网 发表
《本文》有 0 条评论