类型与接口的关系

类型与接口的关系

Posted by 锐玩道 on April 21, 2021

如果❤️我的文章有帮助,欢迎点赞、关注。这是对我继续技术创作最大的鼓励。更多往期文章在我的个人博客

同一类型实现多接口

一个类型能够实现多个接口。并且接口间相互独立,不需要理会对方的实现。 举个例子:学生既可以讲话,也可以走动。我们可以定义出 SayerMover接口,如下:

// Sayer 接口
type Sayer interface {
    say()
}

// Mover 接口
type Mover interface {
    move()
}

Student 可以同时实现 SayerMover接口。

type Student struct {
    name string
}

// 实现Sayer接口
func (s Student) say() {
    fmt.Printf("%s会说早上好\n", s.name)
}

// 实现Mover接口
func (s Student) move() {
    fmt.Printf("%s会靠近\n", s.name)
}

func main() {
    var sayer Sayer
    var mover Mover

    var student = Student{name: "张三"}
    sayer = student
    mover = student
    sayer.say()     // 张三会说早上好
    mover.move()    // 张三会靠近
}

多类型实现同一接口

Golang 中不同类型可以实现同一接口, 该部分上一节已经演示过不过多累述。 这里需要注意的是接口的方法,并没有强制要求由一个类型完全实现,还可以在实现接口的类型嵌入其他类型、结构体来实现。 举个例子:

// WashingMachine 洗衣机
type WashingMachine interface {
    wash()
    dry()
}

// 甩干器
type dryer struct{}
func (d dryer) dry() {
    fmt.Println("甩一甩")
}

// 海尔洗衣机
type haier struct {
    dryer // 嵌入甩干器
}

func (h haier) wash() {
    fmt.Println("洗一洗")
}

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

使用值接收、指针接收 分别实现接口有什么区别呢? 接下来我们通过例子查看一下。

我们分别定义一个 Mover接口、一个 Student结构体

type Mover interface {
    move()
}

type Student struct {}

值接收者实现接口

func (student Student) move() {
    fmt.Println("学生会走动")
}

此时使用 Student类型 实现接口:

func main() {
	var m Mover
	var zhangsan = Student{}     // 张三是Student类型
	m = zhangsan                 // m可以接收Student类型
	m.move()

	var lisi = &Student{}      // 李四是*Student类型
	m = lisi                   // m可以接收*Student类型
	m.move()
}

上面的代码中我们可以看出:使用值接收实现接口后,不管是结构体还是结构体指针 都可以赋值给接口变量 m。因为 Golang 中有针对指针类型变量求值的语法糖,指针&Student{}lisi 内部会自动求值 *lisi。

指针接收者实现接口

同样的代码,再测试一下使用指针接收的区别:

func (student *Student) move() {
    fmt.Println("学生会走动")
}

func main() {
    var m Mover
    var zhangsan = Student{}     // 张三是Student类型
    m = zhangsan                 // m不可以接收Student类型

    var lisi = &Student{}      // 李四是*Student类型
    m = lisi                   // m可以接收*Student类型
    m.move()
}

此时实现Mover接口的是 *Student 类型,所以不能给m传入Student类型的zhangsan,此时m只能存储 *Student 类型的值。