Go 接口

接口的定义

  1. go的接口类型定义了一组行为。

  2. 如果某个 类型 实现了某个接口。那么所以使用这个接口的地方,都支持这种类型。

如果一个变量,他实现了接口里的所有方法,那么他就是实现了这个接口

接口的作用

需求

现在有 狗 和 猫 两个结构体,都能叫,如果被 这个函数调用了,他们都能叫,如果在函数往里传参的时候,指定是穿进去的什么参数。

使用接口解决这个问题

(按照约定,只包含一个方法的)接口的名字由方法名加 [e]r 后缀组成,例如Printer、Reader、Writer、Logger、Converter 等等。还有一些不常用的方式(当后缀 er 不合适时),比如Recoverable,此时接口名以 able 结尾,或者以 I 开头(像 .NET 或 Java 中那样)。

package main

import "fmt"

type dog struct{}
type cat struct{}

// 声明接口
type speaker interface {
	speak() // speak 方法
}

func (d dog) speak() {
	fmt.Println("汪汪叫")
}

func (c cat) speak() {
	fmt.Println("喵喵叫")
}

func da(x speaker) {
	x.speak() // 传进来一个x,无论这个x是什么样式,都打出来
}

func main() {
	var dog1 dog
	var cat1 cat
	da(dog1)
	da(cat1)
}

接口的定义

type 接口的名字 interface{

	方法名1:(参数1,参数2,参数3)(返回值1,返回值2)
	
	方法名1:(参数1,参数2,参数3)(返回值1,返回值2)
	
}

猫狗的另一个例子

package main

import "fmt"

type animal interface {
	move()      // 移动
	eat(string) // 吃东西
}

type dog struct { // 先声明 猫和 狗两个实例
	name string
	feet int
}
type cat struct {
	name string
	feet int // 几条腿
}

func (c cat) eat(foot string) {
	fmt.Println("猫吃啥?", foot) // 猫吃啥?猫吃鱼
}
func (c cat) move() {
	fmt.Println("猫跑了")
}

func (d dog) eat(foot string) {
	fmt.Println("狗吃啥?", foot) //狗吃东西
}
func (d dog) move() {
	fmt.Println("狗跑了")
}

func main() {
	var anmin animal // 声明接口
	dog1 := dog{
		name: "小黑狗",
		feet: 4,
	}

	anmin = dog1
	anmin.move()
	anmin.eat("骨头")

	cat1 := cat{
		name: "小黄猫",
		feet: 8,
	}

	anmin = cat1
	anmin.eat("鱼")
	anmin.move()
}


// 输出
狗跑了
狗吃啥? 骨头
猫吃啥? 鱼  
猫跑了 

值接受者和指针接受者的区别

当接受者为值类型的时候,你可以往里传指针,但是当接受者是指针类型的时候,你不能往里传值。

package main

import "fmt"

type animal interface {
	move()      // 移动
	eat(string) // 吃东西
}

type dog struct { // 先声明 猫和 狗两个实例
	name string
	feet int
}

func (d dog) eat(foot string) {
	fmt.Println("狗吃啥?", foot) //狗吃东西
}
func (d dog) move() {
	fmt.Println("狗跑了")
}

func main() {
	var anmin animal // 声明接口
	dog1 := dog{
		name: "小黑狗",
		feet: 4,
	}

	anmin = dog1
	anmin.move()
	anmin.eat("骨头")

	fmt.Println("****************")
	anmin = &dog1
	anmin.move()
	anmin.eat("骨头")
}

// 输出
狗跑了
狗吃啥? 骨头
****************
狗跑了
狗吃啥? 骨头

值传递的另一个例子

type people interface {
	Speak(string) string
}

type Student struct{}

func (s *Student) Speak(think string) string {
	if think == "sb" {
		return "大帅比"
	} else {
		return "你好"
	}
}

func main() {
	var pe people = &Student{}
	fmt.Println(pe.Speak("sb")) //只能用指针调用
}

嵌套

结构体的嵌套

上边写的都是多个类型实现同一个接口,实际上也可以一个类型实现多个接口。

type eater interface {
	eat(string) // 吃东西
}

type mover interface {
	move() // 实现了move这个接口
}

type dog struct { // 先声明 猫和 狗两个实例
	name string
	feet int
}

func (d dog) eat(foot string) {
	fmt.Println("狗吃啥?", foot) //狗吃东西
}
func (d dog) move() {
	fmt.Println("狗跑了")
}

dog对应这 movereater 这两个接口,而且还可以实现接口的嵌套。

一个接口可以嵌套一个或者多个接口

type ReadWrite interface {
    Read(b Buffer) bool
    Write(b Buffer) bool
}

type Lock interface {
    Lock()
    Unlock()
}

type File interface {
    ReadWrite
    Lock
    Close()
}

空接口

type 接口名字 interface {} // 里面任何东西都不写

空接口没有必要命名,通常定义为如下形式

interface{}  // 空接口

空接口,也就是说所有的类型都实现了这个接口

这样传什么值都可以了。

空接口可以存储任意类型的值

package main

import "fmt"

func main() {
	var m1 = make(map[string]interface{}) // 声明m1
	m1["name"] = "赵"
	m1["age"] = 20
	m1["hopy"] = []string{"吃饭", "睡觉"}
	fmt.Println(m1)
}

// 输出
map[age:20 hopy:[吃饭 睡觉] name:赵]
package main

import "fmt"

// 空接口作为参数
func f1(x interface{}) {
	fmt.Println(x)
	fmt.Printf("%T,%v",x,x)
}

func main() {
	var m1 = make(map[string]interface{}) // 声明m1
	m1["name"] = "赵"
	m1["age"] = 20
	m1["hopy"] = []string{"吃饭", "睡觉"}
	fmt.Println(m1)

	f1("你好")
	f1(15)
	f1(true)
}


// 输出
string,你好15
int,15true
bool,true

8. 把空接口的值取出来

如何取出来呢?就是考猜

package main

import "fmt"

func f1(x interface{}) {
	v, ok := x.(string) // 猜他是什么类型
	if !ok {
		fmt.Println("猜错了")
	} else {
		fmt.Println(v)
	}
}

func main() {
	f1(2)
}

// 输出
猜错了
posted @ 2021-08-05 14:40  沧海一声笑rush  阅读(124)  评论(0编辑  收藏  举报