golang学习笔记5——接口

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yubo_725/article/details/89600205

接口的声明

golang中的接口声明方式如下:

type 接口名 interface {
	方法名(参数) 返回值
}

例子:

// Writer接口
type Writer interface {
	// Write方法,参数为一个字符串
	Write(s string)
}

// Stringer接口
type Stringer interface {
	// String方法,参数为空,返回值为string
	String() string
}

接口的实现

golang中实现接口需要满足两个条件:

  1. 某个类型实现了与接口中的方法具有相同签名的方法
  2. 接口中的方法全部都被某个类型实现

只有同时满足上面两条,才算某个接口被某个类型实现,下面举例说明:

// 定义一个Animal接口,接口中包含Sleep和Eat两个方法
type Animal interface {
	Sleep()
	Eat(string)
}

// 定义一个Dog结构体
type Dog struct {
}

// Dog实现Animal的Sleep方法
func (d *Dog) Sleep() {               // (1)
	fmt.Println("dog is sleeping...")
}

// Dog实现了Animal的Eat方法
func (d *Dog) Eat(food string) {
	fmt.Printf("dog is eating %s\n", food)
}

func main() {
	// 声明一个Animal接口
	var anim Animal
	// 初始化一个Dog结构体
	d := new(Dog)
	// 将Dog赋值给anim
	anim = d                 // (2)
	fmt.Printf("%T\n", d)    // 打印: *main.Dog
	fmt.Printf("%T\n", anim) // 打印: *main.Dog
}

上面的代码展示了Dog结构体实现Animal接口的方法,如果将Dog结构体的Sleep方法增加一个参数,那DogSleep方法签名就与Animal接口中定义的Sleep方法签名不一致,则Dog就不算实现了Animal接口。

例如把上面的代码注释(1)这行修改为如下代码:

func (d *Dog) Sleep(s string) {

则以上代码的注释(2)这行会报错,因为Sleep方法的签名不一致,所以Dog没有实现Animal接口,则无法将d赋值给anim变量

接口与类型

关于接口和类型,有如下几点需要说明:

  • 一个类型可以实现多个接口
  • 一个接口可以被多个类型实现

如下代码所示:

type Door interface {
	OpenDoor()
	CloseDoor()
}

type Window interface {
	OpenWin()
	CloseWin()
}

// 房子
type House struct {
}

// 别墅
type Villa struct {
}

// 房子实现了OpenDoor方法
func (h *House) OpenDoor() {
	fmt.Println("house open door...")
}

// 房子实现了CloseDoor方法
func (h *House) CloseDoor() {
	fmt.Println("house close door...")
}

// 别墅实现了OpenDoor方法
func (v *Villa) OpenDoor() {
	fmt.Println("open villa door...")
}

// 别墅实现了CloseDoor方法
func (v *Villa) CloseDoor() {
	fmt.Println("close villa door...")
}

接口的嵌套组合

type Writer interface {
	Write(string)
}

type Reader interface {
	Read() string
}

// 接口的嵌套组合
type ReadWriter interface {
	Reader
	Writer
}

// Machine实现了ReadWriter接口
type Machine struct {
}

func (m *Machine) Write(s string) {
	fmt.Println("machine write " + s)
}

func (m *Machine) Read() string {
	return "hello"
}

func main() {
	var readWriter ReadWriter
	var reader Reader

	machine := new(Machine)
	machine.Write("haha")

	readWriter = machine
	reader = machine

	s := readWriter.Read()
	fmt.Println(s)

	reader = machine
	reader.Read()
}

接口的转换

举例:鸟和猪都能行走,但鸟可以飞而猪不行,分别定义两个接口:Flyer Walker,鸟需要实现这两个接口,而猪只实现Walker接口,怎么判断一个变量是Flyer或者Walker呢?golang中使用如下方式判断:

f, ok := i.(T)

解释:

  • i表示一个接口变量
  • T表示这个接口要转换成的类型
  • 如果iT类型的变量,则f表示i转换成功后的变量,oktrue,如果转换失败,则ok为false

下面用代码说明:

type Flyer interface {
	Fly()
}

type Walker interface {
	Walk()
}

type Bird struct {
}

func (b *Bird) Fly() {
	fmt.Println("bird fly...")
}

func (b *Bird) Walk() {
	fmt.Println("bird walk...")
}

type Pig struct {
}

func (p *Pig) Walk() {
	fmt.Println("pig walk...")
}

func main() {
	// 数组中装了鸟类和猪类
	objs := []interface{}{new(Bird), new(Pig)}
	// 遍历数组
	for _, item := range objs {
		// 判断元素是否是Flyer
		f, canFly := item.(Flyer)
		// 判断元素是否是Walker
		w, canWalk := item.(Walker)
		if canFly {
			// 是Flyer则调用Fly()
			f.Fly()
		}
		if canWalk {
			// 是Walker则调用Walk()
			w.Walk()
		}
	}
}

打印结果为:

bird fly...
bird walk...
pig walk...

另外接口也可以转为指针类型,比如下面的代码将一个Walker接口变量转为Pig指针:

p := new(Pig)
var walker Walker = p
// 将接口转为指针类型
ptr, ok := walker.(*Pig)
if ok {
	ptr.Walk()
}

空接口

golang中使用interface{}表示空接口,空接口可以表示任何类型的数据,类似于Java中的Object类型,在golang中,空接口可以被赋值为任意类型的值,但反之则不行,例如下面的代码:

// obj是空接口,使用interface{}表示空接口类型
var obj interface{}

// 将整型值赋值给空接口
var a int = 1
obj = a
fmt.Println(obj)

// 将字符串赋值给空接口
s := "hello"
obj = s
fmt.Println(obj)

// 下面的代码报错,不能将空接口赋值给一个字符串
// var str string = obj

下面的代码实现了将任意类型的数据存到map中:

// 定义一个map,其中的键值可以是任意类型
var data = make(map[interface{}]interface{})
data["name"] = "zhangsan"
data[1] = 3.14
data[2.5] = &struct {
	Name  string
	Color string
}{
	Name:  "kenny",
	Color: "black",
}
fmt.Println(data)
展开阅读全文

没有更多推荐了,返回首页