目录


一、接口介绍

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

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

二、基础接口操作方法

1. 定义接口:所有接口后面最好跟上er

// 定义接口 usb
type Usber interface {
	Start()
	Stop()
}

2. 使用接口

定义的Phone结构体中必须要含有接口中的所有方法

// 手机
type Phone struct {
	Name string
}

// 必须得有 Start()和Stop()方法
func (p Phone) Start() {
	fmt.Println(p.Name, "启动了")
}

func (p Phone) Stop() {
	fmt.Println(p.Name, "关机")
}

func main() {
    // 以往调用结构体
	var p = Phone{}
	p.Name = "华为"
	p.Start() // 华为 启动了
	p.Stop()  // 华为 关机

	// 实现接口
	var phone Usber = p
	phone.Start() // 华为 启动了
	phone.Stop()  // 华为 关机
}

3. 实现电脑usb接口连接手机和相机

package main

import "fmt"

// 定义电脑usb接口
type Usber2 interface {
	start()
	stop()
}

// 定义电脑结构体
type Computer struct {
}

// 定义电脑usb工作方式
func (c Computer) Work(u Usber2) {
	u.start()
	u.stop()
}

// 定义手机
type Phone2 struct {
}

func (p Phone2) start() {
	fmt.Println("手机连接成功")
}

func (p Phone2) stop() {
	fmt.Println("手机断开连接")
}

// 定义相机
type Cermail struct {
}

func (c Cermail) start() {
	fmt.Println("相机连接成功")
}

func (c Cermail) stop() {
	fmt.Println("相机断开连接")
}

func main() {
    // 分别定义变量
	p1 := Phone2{}
	c := Cermail{}
	computer := Computer{}
	// 手机连接电脑
	computer.Work(p1) // 手机连接成功 手机连接成功
	// 相机连接电脑
	computer.Work(c) // 相机连接成功 相机断开连接
}

三、空接口

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

1. 空接口定义及基础使用

    var a interface{} // 定义变量a为空接口
	a = "你好 golang"
	fmt.Printf("值:%v 类型:%T\n", a, a) // 值:你好 golang 类型:string

	a = 10
	fmt.Printf("值:%v 类型:%T\n", a, a) // 值:10 类型:int

	a = true
	fmt.Printf("值:%v 类型:%T\n", a, a) // 值:true 类型:bool

2. 空接口作为函数参数

// 空接口作为函数参数,代表该函数接收任意参数
func test(i interface{}) {
	fmt.Printf("值:%v 类型:%T\n", i, i)
}

func main() {
    // 随意传入参数
	test(1)     // 值:1 类型:int
	test("阿西吧") // 值:1 类型:int
	var b = make(map[string]string)
	b["哈哈"] = "嘻嘻"
	test(b) // 值:map[哈哈:嘻嘻] 类型:map[string]string
	var c = []int{1, 2, 3}
	test(c) // 值:[1 2 3] 类型:[]int
}

3. map值实现空接口

    // 空接口作为map,代表可以保存任意值
	var e = make(map[string]interface{})
	e["username"] = "张三"
	e["age"] = 12
	fmt.Println(e) // map[age:12 username:张三]

    var f = make(map[interface{}]interface{})
	f[123] = 456
	f["test"] = 123
	f["fdas"] = "ghu"
	fmt.Println(f) // map[123:456 fdas:ghu test:123]

4. 切片空接口

// 切片空接口
	var g = []interface{}{1, "张三", true}
	fmt.Println(g) // [1 张三 true]

四、类型断言

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

如果我们想要判断空接口中值的类型,那么这个时候就可以使用类型断言,其语法格式:x.(T)

其中: x : 表示类型为 interface{}的变量  T : 表示断言 x 可能是的类型。

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

1. 断言的基础使用

    // 断言基础使用
	var h interface{}
	h = "张三"
	v, ok := h.(string)
	if ok {
		fmt.Println(v) // 张三
	} else {
		fmt.Println("不是string类型")
	}

2. 多次断言配合swtich使用

package main

import "fmt"

// 多次断言配合switch使用,另外类型.(type)只能配合switch使用
func vifType(s interface{}) {
	switch s.(type) {
	case string:
		fmt.Println("string")
	case int:
		fmt.Println("int")
	case bool:
		fmt.Println("bool")
	default:
		fmt.Println("no search")
	}
}

func main() {
    // 多次断言配合switch使用
	vifType("abcd")     // string
	vifType(123)        // int
	vifType(true)       // bool
	vifType(int64(123)) // no search
}

3. 注意

因为空接口可以存储任意类型值的特点,所以空接口在 Go 语言中的使用十分广泛。

关于接口需要注意的是:只有当有两个或两个以上的具体类型必须以相同的方式进行处理时才需要定义接口。不要为了接口而写接口,那样只会增加不必要的抽象,导致不必要的运行时损耗。

4. 练习

回到上文中提到的电脑usb接口中,判断是phone还是camera,分别执行方法

package main

import "fmt"

type Usber interface {
	start()
	stop()
}

type Phone struct {
}

func (p Phone) start() {
	fmt.Println("手机连接")
}

func (p Phone) stop() {
	fmt.Println("手机断开")
}

type Camera struct {
}

func (c Camera) start() {
	fmt.Println("相机连接")
}

func (c Camera) stop() {
	fmt.Println("相机断开")
}

type Computer struct {
}

func (c Computer) Work(usb Usber) {
	if _, ok := usb.(Phone); ok {
		usb.start()
	} else {
		usb.stop()
	}
}

func main() {
    computer := Computer{}
	p := Phone{}
	c := Camera{}

	computer.Work(p) // 手机连接
	computer.Work(c) // 相机断开
}