Go语言基础之接口

视频地址:
https://www.bilibili.com/video/av76169197?p=65
学习笔记:
https://www.liwenzhou.com/posts/Go/12_interface/

接口(interface)

在Go语言中接口(interface)是一种类型,一种特殊的,抽象的类型,它规定了变量有哪些方法.

在编程中会遇到以下场景:

我不关心一个变量是什么类型,我只关心能调用它的什么方法 .

接口的定义:

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

示例1:

package main

import "fmt"

type animal interface {
	move()
	eat(string)
}

type cat struct {
	name string
	feet int8
}

func (c cat) move() {
	fmt.Printf("走猫步...")
}

func (c cat) eat(food string) {
	fmt.Printf("%s吃%s", c.name, food)
}

type checken struct {
	name string
	feet int8
}

func (cc checken) move() {
	fmt.Printf("走鸡步...")
}

func (cc checken) eat(food string) {
	fmt.Printf("%s吃%s \n", cc.name, food)
}

func eat(a animal, food string) {
	a.eat(food)
}

func main() {
	var a1 animal
	c1 := cat{
		name: "淘气",
		feet: 4,
	}
	a1 = c1
	c1.eat("小黄鱼")
	fmt.Println(a1) //猫吃小黄鱼{淘气 4}

	var kfc = checken{
		name: "小鸡鸡",
		feet: 4,
	}
	a1 = kfc
	fmt.Println(a1) //{小鸡鸡 4}
	a1.eat("虫子")    //小鸡鸡吃虫子

	eat(c1, "小黄鱼") //淘气吃小黄鱼
	fmt.Println()
	eat(kfc, "虫子") //小鸡鸡吃虫子
}

用来给变量\参数\返回值等设置类型

接口的实现:

实现接口的条件:
一个对象只要实现了接口中所有的方法,那么就实现了这个接口。换句话说,接口就是一个需要实现的方法列表。

代码示例一:

package main

import "fmt"

type Speaker interface {
	speak()
}

type cat struct{}

type dog struct{}

type person struct{}

func (c cat) speak() {
	fmt.Println("喵喵喵")
}
func (d dog) speak() {
	fmt.Println("汪汪汪")
}

func (p person) speak() {
	fmt.Println("啊啊啊")
}

func da(s Speaker) {
	s.speak()
}

func main() {
	a := cat{}    // 实例化一个cat
	b := dog{}    // 实例化一个dog
	p := person{} // 实例化一个人

	var x Speaker // 声明一个Speaker类型的变量x
	x = a         // 可以把cat实例直接赋值给x
	x.speak()     //喵喵喵

	x = b     // 可以把dog实例直接赋值给x
	x.speak() //汪汪汪

	x = p     // 可以把dog实例直接赋值给x
	x.speak() //啊啊啊

	da(a) //喵喵喵
	da(b) //汪汪汪
	da(p) //啊啊啊

}

代码示例二:

package main

import "fmt"

type cater interface {
	run()
}

type falali struct {
	// fmt.Printf("%s 速度70迈 ~\n",)
	brand string
}

func (f falali) run() {
	fmt.Printf("%s 速度70迈\n", f.brand)
}

type boshiji struct {
	brand string
}

func (b boshiji) run() {
	fmt.Printf("%s 速度100迈\n", b.brand)
}

func drive(c cater) {
	c.run()
}
func main() {
	f := falali{
		brand: "法拉力",
	}
	f.run() //法拉力 速度70迈

	var b = boshiji{
		brand: "宝时捷",
	}
	b.run() //宝时捷 速度100迈

	drive(f) //法拉力 速度70迈
	drive(b) //宝时捷 速度100迈

}

示例三:

package main

import "fmt"

type animal interface {
	move()
	eat(string)
}

type cat struct {
	name string
	feet int8
}

func (c cat) move() {
	fmt.Printf("走猫步...")
}

func (c cat) eat(food string) {
	fmt.Printf("%s吃%s", c.name, food)
}

type checken struct {
	name string
	feet int8
}

func (cc checken) move() {
	fmt.Printf("走鸡步...")
}

func (cc checken) eat(food string) {
	fmt.Printf("%s吃%s \n", cc.name, food)
}

func eat(a animal, food string) {
	a.eat(food)
}

func main() {
	var a1 animal
	c1 := cat{
		name: "淘气",
		feet: 4,
	}
	a1 = c1
	c1.eat("小黄鱼")
	fmt.Println(a1) //猫吃小黄鱼{淘气 4}

	var kfc = checken{
		name: "小鸡鸡",
		feet: 4,
	}
	a1 = kfc
	fmt.Println(a1) //{小鸡鸡 4}
	a1.eat("虫子")    //小鸡鸡吃虫子

	eat(c1, "小黄鱼") //淘气吃小黄鱼
	fmt.Println()
	eat(kfc, "虫子") //小鸡鸡吃虫子
}


接口值

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

类型与接口的关系

1.一个类型实现多个接口

一个类型可以同时实现多个接口,而接口间彼此独立,不知道对方的实现。 例如,狗可以叫,也可以动。我们就分别定义Sayer接口和Mover接口,如下: Mover接口。

dog既可以实现Sayer接口,也可以实现Mover接口。

package main

import "fmt"

/**
类型与接口的关系
一个类型实现多个接口

一个类型可以同时实现多个接口,而接口间彼此独立,不知道对方的实现。
例如,狗可以叫,也可以动。我们就分别定义Sayer接口和Mover接口,如下: Mover接口。

*/

type Sayer interface {
	say()
}

type Mover interface {
	move()
}

type dog struct {
	name string
}

//dog既可以实现Sayer接口,也可以实现Mover接口。
func (d dog) say() {
	fmt.Printf("%s汪汪汪\n", d.name)
}
func (d dog) move() {
	fmt.Printf("%s会move \n", d.name)
}
func main() {
	var s Sayer
	var m Mover
	var d = dog{
		name: "xiaopang",
	}
	s = d
	s.say() //xiaopang汪汪汪

	m = d
	m.move() //xiaopang会move
}

2.多个类型实现同一接口

Go语言中不同的类型还可以实现同一接口 首先我们定义一个Mover接口,它要求必须有一个move方法。

例如狗可以动,汽车也可以动,可以使用如下代码实现这个关系:

package main

import "fmt"

// Mover 接口
type Mover interface {
	move()
}

//例如狗可以动,汽车也可以动,可以使用如下代码实现这个关系:
type dog struct {
	name string
}

type car struct {
	brand string
}

// dog类型实现Mover接口
func (d dog) move() {
	fmt.Printf("%s会跑\n", d.name)
}

// car类型实现Mover接口
func (c car) move() {
	fmt.Printf("%s速度70迈\n", c.brand)
}

//这个时候我们在代码中就可以把狗和汽车当成一个会动的物体来处理了,
//不再需要关注它们具体是什么,只需要调用它们的move方法就可以了。
func main() {
	var x Mover
	var a = dog{name: "旺财"}
	var b = car{brand: "保时捷"}
	x = a
	x.move() //旺财会跑
	x = b
	x.move() //保时捷速度70迈
}

3.嵌入其他类型或者结构体来实现同一个接口

一个接口的方法,不一定需要由一个类型完全实现,接口的方法可以通过在类型中嵌入其他类型或者结构体来实现。

package main

import "fmt"

//一个接口的方法,不一定需要由一个类型完全实现,接口的方法可以通过在类型中嵌入其他类型或者结构体来实现。

// WashingMachine 洗衣机
type WashingMachine interface {
	wash()
	dry()
}

// 甩干器
type dryer struct{}

// 实现WashingMachine接口的dry()方法
func (d dryer) dry() {
	fmt.Println("甩一甩")
}

// 海尔洗衣机
type haier struct {
	dryer //嵌入甩干器
}

// 实现WashingMachine接口的wash()方法
func (h haier) wash() {
	fmt.Println("洗刷刷")
}

func main() {
	var w WashingMachine
	w = haier{}
	w.dry()  //甩一甩
	w.wash() //洗刷刷
}

接口嵌套

package main

import "fmt"
//接口与接口间可以通过嵌套创造出新的接口。
//Sayer接口
type Sayer interface {
	say()
}

//Move接口
type Mover interface {
	move()
}

// 接口嵌套
type animal interface {
	Sayer
	Mover
}
type cat struct {
	name string
}

func (c cat) say() {
	fmt.Printf("%s 会说话. \n", c.name)
}
func (c cat) move() {
	fmt.Printf("%s 会运动. \n", c.name)
}

func main() {
	var x animal
	var c = cat{
		name: "花花",
	}
	x = c
	x.say()  //花花 会说话.
	x.move() //花花 会运动.

	c = cat{name: "花花"}
	c.say()  //花花 会说话.
	c.move() //花花 会运动.

}

posted @ 2020-01-12 23:13  HaimaBlog  阅读(260)  评论(0编辑  收藏  举报