值接收者和指针接收者实现接口的区别

值接收者和指针接收者实现接口的区别

使用值接收者实现接口和使用指针接收者实现接口有什么区别呢?接下来我们通过一个例子看一下其中的区别。

我们有一个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))
}

三、总结

  1. 如果采用的是全部都是值接收者,那么既可以将实例化好的结构体对象赋值给接口变量,也可以将实例化好的结构体对象的指针赋值给接口变量
  2. 如果采用的包含指针接收者,那么只能将实例化好的结构体对象的指针赋值给接口变量
posted @ 2021-11-01 22:31  RandySun  阅读(249)  评论(0编辑  收藏  举报