值接收者和指针接收者实现接口的区别
值接收者和指针接收者实现接口的区别
使用值接收者实现接口和使用指针接收者实现接口有什么区别呢?接下来我们通过一个例子看一下其中的区别。
我们有一个Mover
接口和一个dog
结构体。
type Mover interface {
move()
}
type dog struct {}
一、 值接收者实现接口
func (d dog) move() {
fmt.Println("狗会动")
}
此时实现接口的是dog
类型:
func main() {
var x Mover
var wangcai = dog{} // 旺财是dog类型
x = wangcai // x可以接收dog类型
var fugui = &dog{} // 富贵是*dog类型
x = fugui // x可以接收*dog类型
x.move()
}
从上面的代码中我们可以发现,使用值接收者实现接口之后,不管是dog结构体还是结构体指针dog类型的变量都可以赋值给该接口变量。因为Go语言中有对指针类型变量求值的语法糖,dog指针fugui
内部会自动求值。
二、指针接收者实现接口
同样的代码我们再来测试一下使用指针接收者有什么区别:
func (d *dog) move() {
fmt.Println("狗会动")
}
func main() {
var x Mover
var wangcai = dog{} // 旺财是dog类型
x = wangcai // x不可以接收dog类型
var fugui = &dog{} // 富贵是*dog类型
x = fugui // x可以接收*dog类型
}
此时实现Mover
接口的是*dog
类型,所以不能给x
传入dog
类型的wangcai,此时x只能存储*dog
类型的值。
下面的代码是否能通过编译?
type People interface {
Speak(string) string
}
type Student struct{}
func (stu *Student) Speak(think string) (talk string) {
if think == "sb" {
talk = "你是个大帅比"
} else {
talk = "您好"
}
return
}
func main() {
// var peo People = Student{} // 不能通过
var peo People = &Student{} // 能通过 因为实现的接口为指针接收者
think := "bitch"
fmt.Println(peo.Speak(think))
}
三、总结
- 如果采用的是全部都是值接收者,那么既可以将实例化好的结构体对象赋值给接口变量,也可以将实例化好的结构体对象的指针赋值给接口变量
- 如果采用的包含指针接收者,那么只能将实例化好的结构体对象的指针赋值给接口变量
在当下的阶段,必将由程序员来主导,甚至比以往更甚。