golang学习笔记5——接口

Posted yubo_725

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang学习笔记5——接口相关的知识,希望对你有一定的参考价值。

接口的声明

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 := []interfacenew(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)

以上是关于golang学习笔记5——接口的主要内容,如果未能解决你的问题,请参考以下文章

golang学习笔记

Java学习笔记3.7.3 抽象类接口与多态 - 多态

学习笔记Golang之Gorm学习笔记

golang的面向对象实现

JavaScript面向对象编程指南——学习笔记1

Golang学习笔记-基础数据类型