Golang中的接口

Golang中的接口

1.接口的介绍

1.现实生活中的接口

现实生活中手机、相机、U盘都可以和电脑的USB接口建立连接。我们不需要关注USB卡槽大小是否一样,因为所有的USB接口都是按照同意的标准来设计的。

2.Golang中的接口(Interface)

Golang中的接口是一种抽象数据类型,Golang中接口定义了对象的行为规范,只定义规范不实现。接口中定义的规范由具体的对象来实现。

通俗的讲接口就是一个标准,它是对一个对象的行为和规范进行约定,约定实现接口的对象必须得按照接口的规范。

2.Golang接口的定义

在Golang中接口(interface)是一种类型,一种抽象的类型。接口(interface)是一组函数method的集合,Golnag中的接口不能包含任何变量。

在Golang中接口中的所有方法都没有方法体,接口定义了一个对象的行为规范,只定义规范不实现。接口体现了程序设计的多态和高内聚低耦合的思想。

Golang中的接口也是一种数据类型,不需要显示实现。只需要一个变量含有接口类型中的所有方法,那么这个变量就实现了这个接口。

Golang中每个接口由数个方法组成,接口的定义格式如下:

type 接口名 interface {
    方法名1(参数列表1) 返回值列表1
    方法名2(参数列表2) 返回值列表2
    ...
}

其中:

  • 接口名:使用type将接口定义为自定义类型的类型名。Go语言的接口在命名时,一般会在单词后面添加er,如有写操作的接口叫Writer,有字符串功能的接口叫Stringer等。接口名最好能突出该接口的类型含义。
  • 方法名:当方法名首字母时大写且这个接口类型首字母也是大写时,这个方法可以被接口所在的包(package)之外的代码访问
  • 参数列表、返回值列表:参数列表和返回值列表中的参数变量名可以省略。

3.空接口

Golang中的接口可以不定义任何方法,没有定义任何方法的接口就是空接口。空接口表示没有任何约束,因此任何类型变量都可以实现空接口。

空接口在实际项目中用的是非常多的,用空接口可以表示任意数据类型

1.空接口作为函数的参数

使用空接口实现可以接收任意类型的函数参数

func show(a interface{}) {
fmt.Printf("type:%T value:%v\n", a, a)

}

2.map的值实现空接口

使用空接口实现可以保存任意值的字典

//空接口作为map值
var studentInfo = make(map[string]interface{})
studentInfo["name"] = "zhangsan"
studentInfo["age"] = 18
studentInfo["married"] = false
fmt.Println(studentInfo)

3.切片实现空接口

var slice = []interface{}{"zhangsan", 10, true, 2.2}
fmt.Println(slice)

4.类型断言

一个接口的值(简称接口值)是由一个具体类型和值两部分组成的。这两部分分别称为接口的动态类型和动态值。

如果想要判断空接口中值的类型,可以使用类型断言,语法格式为:

x.(T)

其中:

  • x:表示类型为interface的变量
  • T:表示断言x可能是的类型

该语法返回两个参数,第一个参数是x转化为T类型后的变量,第二个是一个布尔值,若为true则表示断言成功,为false则表示断言失败。

5.结构体值接收者和指针接收者实现接口的区别

值接收者
如果结构体中的方法是值接收者,那么实例化后的结构体类型和结构体指针类型都可以赋值给接口变量

指针接收者
如果结构体中的方法是指针接收者,那么实例化后的结构体指针类型可以赋值给接口变量,结构体类型不能赋值给接口变量

6.一个结构体实现多个接口

Golang中一个结构体可以实现多个接口

type Animaler1 interface {
    SetAge(int)
}

type Animaler2 interface {
    GetAge() int
}

type Bird struct {
    Age int
}

func (b *Bird) SetAge(age int) {
    b.Age = age
}

func (b Bird) GetAge() int {
    return b.Age
}

var b = &Bird{
	Age: 3,
}
var b1 Animaler1 = b     //表示让Bird实现Animaler1接口
var b2 Animaler2 = b     //表示让Bird实现Animaler2接口
fmt.Println(b2.GetAge()) //3
b1.SetAge(5)
fmt.Println(b2.GetAge()) //5

7.接口嵌套

接口与接口之间可以通过嵌套创造出新的接口

8.Golang中空接口和类型断言使用细节

空接口和类型断言结合使用

代码:

package main

import "fmt"

//定义一个Usber接口让Phone和Camera结构体实现这个接口
type Usber interface {
	start()
	stop()
}

//如果接口里面有方法的话,必须要通过结构体或者通过自定义类型实现这个接口
type Phone struct {
	Name string
}

//手机要实现Usb接口的话,必须要实现usb接口中的所有方法
func (p Phone) start() { //Phone值接收者,*Phone为指针接收者
	fmt.Println(p.Name, "start")
}

func (p Phone) stop() {
	fmt.Println(p.Name, "stop")
}

type Camera struct {
}

func (c Camera) start() {
	fmt.Println("Camera start")
}

func (c Camera) stop() {
	fmt.Println("Camera stop")
}

func (c Camera) run() {
	fmt.Println("Camera run")
}

type Computer struct {
}

func (c Computer) work(usb Usber) {
	usb.start()
	usb.stop()
}

//空接口
type A interface{} //空接口表示没有任何约束,任何类型变量都可以实现空接口。

//空接口作为函数的参数
func show(a interface{}) {
	fmt.Printf("type:%T value:%v\n", a, a)
}

//定义一个方法,可以传入任意数据类型,然后根据不同的类型实现不同的功能
func MyPrint1(x interface{}) {
	if _, ok := x.(string); ok {
		fmt.Println("stirng类型")
	} else if _, ok := x.(int); ok {
		fmt.Println("int类型")
	} else if _, ok := x.(bool); ok {
		fmt.Println("bool类型")
	}
}

//x.(type)判断一个变量的类型,这个语句只能用在switch语句里面
func MyPrint2(x interface{}) {
	switch x.(type) {
	case int:
		fmt.Println("int类型")
	case string:
		fmt.Println("string类型")
	case bool:
		fmt.Println("bool类型")
	default:
		fmt.Println("不支持的数据类型")
	}
}

//类型断言结合接口的使用
type Laptop struct{}

func (l Laptop) work(usb Usber) {
	//判断usb的类型
	if _, ok := usb.(Phone); ok {
		usb.start()
	} else {
		usb.stop()
	}

}

//指针接收者
type Udisk struct {
	Name string
}

func (u *Udisk) start() { //*Udisk为指针接收者
	fmt.Println(u.Name, "start")
}

func (u *Udisk) stop() {
	fmt.Println(u.Name, "stop")
}

//定义一个Animal接口,Animal中定义两个方法,分别是SetName和GetName,分别上Dog和Cat结构体实现这个方法
type Animaler interface {
	SetName(string)
	GetName() string
}

type Dog struct {
	Name string
}

func (d *Dog) SetName(name string) {
	d.Name = name
}

func (d Dog) GetName() string {
	return d.Name
}

type Cat struct {
	Name string
}

func (c *Cat) SetName(name string) {
	c.Name = name
}

func (c Cat) GetName() string {
	return c.Name
}

//一个结构体实现多个接口
type Animaler1 interface {
	SetAge(int)
}

type Animaler2 interface {
	GetAge() int
}

type Bird struct {
	Age int
}

func (b *Bird) SetAge(age int) {
	b.Age = age
}

func (b Bird) GetAge() int {
	return b.Age
}

//嵌套接口
type Ainterface interface {
	SetSex(string)
}

type Binterface interface {
	GetSex() string
}

type Animaler3 interface {
	Ainterface
	Binterface
}

type Duck struct {
	Sex string
}

func (d *Duck) SetSex(sex string) {
	d.Sex = sex
}

func (d Duck) GetSex() string {
	return d.Sex
}

type Address struct {
	Name  string
	Phone int
}

func main() {

	// p := Phone{
	// 	Name: "iPhone",
	// }
	// // p.start() //iPhone start

	// var p1 Usber //golang中接口就是一个数据类型

	// p1 = p //表示手机实现Usb接口

	// p1.start()
	// p1.stop()

	// c := Camera{}

	// var c1 Usber = c //表示Camera实现了USB接口
	// c1.start()       //Camera start
	// c1.stop()        //Camera stop

	// // c1.run() //错误调用:c1.run undefined (type Usber has no field or method run)

	// c.run()

	// var computer = Computer{}
	// var phone = Phone{
	// 	Name: "xiaomi",
	// }
	// var camera = Camera{}

	// computer.work(phone)
	// computer.work(camera)

	//空接口

	// var a A
	// var str = "Hello Golang"
	// a = str                           //让字符串实现A这个接口
	// fmt.Printf("值:%v, 类型:%T\n", a, a) //值:Hello Golang, 类型:string

	// var num = 20
	// a = num                           //表示让int类型实现A这个接口
	// fmt.Printf("值:%v, 类型:%T\n", a, a) //值:20, 类型:int

	// var flag = true
	// a = flag                          //表示让bool类型实现A这个接口
	// fmt.Printf("值:%v, 类型:%T\n", a, a) //值:true, 类型:bool

	//golang中空接口可以直接当作类型来使用,可以表示任意类型
	// var a interface{}
	// a = 20
	// fmt.Printf("值:%v, 类型:%T\n", a, a) //值:20, 类型:int
	// a = "hello Golang"
	// fmt.Printf("值:%v, 类型:%T\n", a, a) //值:hello Golang, 类型:string
	// a = true
	// fmt.Printf("值:%v, 类型:%T\n", a, a) //值:true, 类型:bool

	// show(8)        //type:int value:8
	// show("string") //type:string value:string
	// slice := []int{1, 2, 3, 4}
	// show(slice) //type:[]int value:[1 2 3 4]

	// var studentInfo = make(map[string]interface{})
	// studentInfo["name"] = "zhangsan"
	// studentInfo["age"] = 18
	// studentInfo["married"] = false
	// fmt.Println(studentInfo)//map[age:18 married:false name:zhangsan]

	// var slice = []interface{}{"zhangsan", 10, true, 2.2}
	// fmt.Println(slice) //[zhangsan 10 true 2.2]

	//类型断言
	// var a interface{}

	// a = "string"

	// // v, ok := a.(string)//a就是一个string类型,值是: string
	// v, ok := a.(int) //断言失败
	// if ok {
	// 	fmt.Println("a就是一个string类型,值是:", v)
	// } else {
	// 	fmt.Println("断言失败")
	// }

	// MyPrint1("你好Golang") //stirng类型

	// MyPrint2("test string") //string类型
	// MyPrint2(16)            //int类型
	// MyPrint2(true)          //bool类型

	// var laptop = Laptop{}
	// var phone = Phone{
	// 	Name: "huawei",
	// }

	// var camera = Camera{}
	// laptop.work(phone)
	// laptop.work(camera)

	//结构体值接收者实例化后的结构体类型和结构体指针类型都可以赋值给接口变量

	// var p1 = Phone{
	// 	Name: "vivo",
	// }

	// var p2 Usber = p1 ////表示让phone实现Usb接口
	// p2.start()        //vivo start

	// var p3 = &Phone{
	// 	Name: "oppo",
	// }

	// var p4 Usber = p3 ////表示让phone实现Usb接口
	// p4.start()        //oppo start

	//指针接收者
	/*
		错误写法:
		var u1 = Udisk{
			Name: "kingston",
		}

		var u2 Usber = u1 ////表示让phone实现Usb接口
		u2.start()        //cannot use u1 (type Udisk) as type Usber in assignment:	Udisk does not implement Usber (start method has pointer receiver)
	*/

	// var u1 = &Udisk{
	// 	Name: "kingston",
	// }

	// var u2 Usber = u1 ////表示让udisk实现Usb接口
	// u2.start()        //kingston start

	//Dog实现Animal接口
	// var d1 = &Dog{
	// 	Name: "xiaohuang",
	// }
	// var d2 Animaler = d1
	// fmt.Println(d2.GetName()) //xiaohuang
	// d2.SetName("daqing")
	// fmt.Println(d2.GetName()) //daqing

	//Cat实现Animal接口
	// var c1 = &Cat{
	// 	Name: "xiaohua",
	// }
	// var c2 Animaler = c1
	// fmt.Println(c2.GetName()) //xiaohua
	// c2.SetName("Ameng")
	// fmt.Println(c2.GetName()) //Ameng

	//一个结构体实现多个接口
	// var b = &Bird{
	// 	Age: 3,
	// }
	// var b1 Animaler1 = b     //表示让Bird实现Animaler1接口
	// var b2 Animaler2 = b     //表示让Bird实现Animaler2接口
	// fmt.Println(b2.GetAge()) //3
	// b1.SetAge(5)
	// fmt.Println(b2.GetAge()) //5

	//嵌套接口
	// d := &Duck{
	// 	Sex: "Male",
	// }

	// var d1 Animaler3 = d
	// d1.SetSex("Female")
	// fmt.Println(d1.GetSex()) //Female

	var userinfo = make(map[string]interface{})
	userinfo["username"] = "zhangsan"
	userinfo["age"] = 18
	userinfo["hobby"] = []string{"sleep", "eat"}

	// fmt.Println(userinfo["age"])   //18
	// fmt.Println(userinfo["hobby"]) //[sleep eat]
	// // fmt.Println(userinfo["hobby"][1]) //invalid operation: userinfo["hobby"][1] (type interface {} does not support indexing)

	var address = Address{
		Name:  "lisi",
		Phone: 1234567890987,
	}

	fmt.Println(address.Name) //lisi
	userinfo["address"] = address
	fmt.Println(userinfo["address"]) //{lisi 1234567890987}
	// name := userinfo["address"].Name//userinfo["address"].Name undefined (type interface {} is interface with no methods)
	// fmt.Println(name)

	hobby2, _ := userinfo["hobby"].([]string)
	fmt.Println(hobby2[1]) //eat

	address2, _ := userinfo["address"].(Address)
	fmt.Println(address2.Name) //lisi

}