教程 > Go 教程 > Go 高级 阅读:714

Go 语言接口的两种实现方式

本章我们介绍Go 语言接口的高级用法,主要包括接口的两种实现方式,通过指针接收器实现的接口和值接收器实现的接口。关于接口的基本概念和用法,参考我们的 Go语言接口 Interface 详解

使用指针接收器与值接收器实现接口

我们在Go语言接口 Interface 详解中讨论的所有示例接口都是使用值接收器实现的。也可以使用指针接收器来实现接口。使用指针接收器实现接口时有一个微妙之处需要我们注意一下。首先我们看下面的示例

package main

import "fmt"

type Describer interface {  
    Describe()
}
type Person struct {  
    name string
    age  int
}

func (p Person) Describe() { // 使用值接收器实现接口  
    fmt.Printf("%s is %d years old\n", p.name, p.age)
}

type Address struct {  
    state   string
    country string
}

func (a *Address) Describe() { // 使用指针接收器实现接口
    fmt.Printf("State %s Country %s", a.state, a.country)
}

func main() {  
    var d1 Describer
    p1 := Person{"Sam", 25}
    d1 = p1
    d1.Describe()
    p2 := Person{"James", 32}
    d1 = &p2
    d1.Describe()

    var d2 Describer
    a := Address{"Tom", "USA"}

    /* 下面注释如果去掉的话,使 d2 = a。则会在编译的时候报错。
                不能将 Address 类型的a变量赋值给Describer类型的d2变量
    */
    //d2 = a

    d2 = &a // 此行代码可以正常执行,因为Describer是由Address 指针实现的
    d2.Describe()
}

运行示例

在上面的程序中,Person结构体Describer使用值接收器实现了接口 Describer。Address结构体使用指针接收器实现接口Describer。

上面程序执行结果如下

Sam is 25 years old
James is 32 years old
State Tom Country USA

上面的程序中,如果将 d2=&a 注释,将 d2=a的注释打开。

func main() {  
    var d1 Describer
    ...
    var d2 Describer
    a := Address{"Tom", "USA"}
        ...
    d2 = a

    // d2 = &a  // 此行代码可以正常执行,因为Describer是由Address 指针实现的
    d2.Describe()
}

则会报如下的错误

./main.go:41:8: cannot use a (type Address) as type Describer in assignment:
    Address does not implement Describer (Describe method has pointer receiver)

运行示例

出现上面的情况的原因是,Describer接口是由 Address 指针接收器实现的。而 Address类型的变量 a 是一个值类型。Address 并没有实现接口 Describer。但是我们之前在 Go 语言方法也介绍过,指针接收器的方法既可以使用指针方式调用也可以使用值方式进行调用。那为什么在接口这里就出现问题了呢?

原因是,对任何已经是指针或可以获取其地址的对象调用指针值方法是合法的。存储在接口中的具体值是不可寻址的,因此编译器不可能自动获取到 a 变量的地址,因此此代码会报错。

查看笔记

扫码一下
查看教程更方便