【Go语言学习】——接口

接口


参考博客

接口是一种类型,可以做参数,变量,返回值设置类型。它不用关心具体的类型,只关心调用什么方法。也就是定义了一个行为规范,只定义规范不实现,由具体的对象来实现规范的细节。
只要一个变量实现了接口中规定的所有的方法,那么就是这个接口的变量。
接口是一种动态引用类型,包括了值的类型和值的类型,会随着给他赋值的类型的值和类型进 行变换

package main

import "fmt"

// 接口格式
// type 接口类型名 interface{
//     方法名1( 参数列表1 ) 返回值列表1
//     方法名2( 参数列表2 ) 返回值列表2
//     …
// }
// 接口类型名常用er结尾
//将具有同样的方法的类型定义为一种类型,这样调用共同的方法时可以直接用接口的类型

type speaker interface {
	speak() //只要实现了speak方法的变量都是Speaker类型
}

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("啊啊啊~")
}

//只要实现了speak方法都都是speaker类型,这些类型都能作为函数的参数
func attack(x speaker) {
	x.speak()
}
func main() {
	var c1 cat
	var d1 dog
	var p1 person
	var x speaker
	attack(c1)
	attack(d1)
	attack(p1)
	//可以直接将属于speaker类型的实例赋值给speaker类型的变量,然后执行对应的方法
	//接口类型的变量存储变量的类型和变量的值,所以根据给它赋值的变量会自动去改变类型和值
	x = c1 //变为cat类型
	fmt.Printf("%T\n", x)
	attack(x)
	x = d1 //变为dog类型
	fmt.Printf("%T\n", x)
	attack(x)

}

package main

import "fmt"

//接口里的方法的参数和返回值可以只写类型,不写名称
//要实现所有的方法才能是这个接口类型,注意名字相同但参数不同的不算同一个函数
type animal interface {
	move()
	eat(string)
}

type cat struct {
	name string
	feet int8
}

type chicken struct {
	feet int8
}

func (c chicken) move() {
	fmt.Println("鸡在跑")
}

func (c chicken) eat() {
	fmt.Println("鸡吃饲料")
}
func (c cat) move() {
	fmt.Println("猫在跑")
}

func (c cat) eat(food string) {
	fmt.Printf("猫吃%s\n", food)
}
func main() {
	var a1 animal
	c1 := chicken{
		feet: 2,
	}
	c2 := cat{
		feet: 4,
		name: "喵喵",
	}
	fmt.Println(c1, c2)
	c1.move()
	c1.eat()
	// a1 = c1出错因为chicken实现的eat方法不是interface里要求的带参数的类型,所以不算
	a1 = c2
	a1.eat("小黄鱼")
	fmt.Println(a1)
}

  • 值接收者和指针接收者实现接口

    使用值接受者实现所有的接口的方法,那么接口变量能够存储该结构体本身和结构体的指针
    使用指针接受者实现所有的接口方法,那么接口变量只能够存储该结构体的指针

    package main
    
    import "fmt"
    
    type animal interface {
    	move()
    	eat(string)
    }
    
    type cat struct {
    	name string
    	feet int8
    }
    
    //使用值接受者实现所有接口的方法
    func (c cat) move() {
    	fmt.Println("猫在跑")
    }
    
    func (c cat) eat(food string) {
    	fmt.Printf("猫吃%s\n", food)
    }
    
    type chicken struct {
    	feet int8
    }
    
    //使用指针接受者实现所有接口的方法
    func (c *chicken) move() {
    	fmt.Println("鸡在跑")
    }
    
    func (c *chicken) eat(food string) {
    	fmt.Printf("鸡吃%s\n", food)
    }
    func main() {
    	//使用值接受者实现所有的接口方法,那么接口变量可以存该类型的结构体类型和结构体指针类型
    	c1 := cat{
    		name: "tom",
    		feet: 4}
    	c2 := &cat{
    		name: "假老练",
    		feet: 4}
    	var a animal
    	a = c1
    	fmt.Println(a)
    	a = c2
    	fmt.Println(a)
    	//使用指针接受者实现所有的接口方法,那么接口变量只能存该结构体的指针类型
    	// c3 := chicken{
    	// 	feet: 4}
    	c4 := &chicken{
    		feet: 8}
    	// a = c3出错,因为使用的指针接受者实现接口方法后,接口类型智能接受结构体指针类型
    	fmt.Println(a)
    	a = c4
    	fmt.Println(a)
    }
    
    
  • 接口与类型的关系

    一个类型可以实现多个接口,多个类型可以实现一个接口

    package main
    
    import "fmt"
    
    type Sayer interface {
    	say()
    }
    
    type Mover interface {
    	move()
    }
    
    type dog struct {
    	name string
    }
    
    func (d dog) say() {
    	fmt.Printf("%s会叫汪汪汪\n", d.name)
    }
    
    func (d dog) move() {
    	fmt.Printf("%s会动\n", d.name)
    }
    
    type car struct {
    	brand string
    }
    
    func (c car) move() {
    	fmt.Printf("%s在公路上飞奔\n", c.brand)
    }
    
    func main() {
    	a := dog{name: "旺财"}
    	//一个类型可以实现多个接口
    	a.say()
    	a.move()
    	//多个类型可以实现同一个接口
    	b := car{brand: "保时捷"}
    	b.move()
    }
    
  • 接口的嵌套

    接口的方法可以通过在类型中嵌入其他类型或者结构体来实现,即嵌入一个实现了一个方法的结构体,则被嵌入的结构体也有了这个方法

    接口和接口之间直接嵌套可以创造出新的接口

    package main
    
    import "fmt"
    
    type WashingMachine interface {
    	wash()
    	dry()
    }
    
    type dryer struct{}
    
    func (d dryer) dry() {
    	fmt.Println("甩一甩")
    }
    
    //接口的方法可以通过在类型中嵌入其他类型或者结构体来实现
    //将结构体嵌入,则被嵌入的结构体也有这个方法
    type haier struct {
    	dryer
    }
    
    //haier实现另外一个方法,则满足了interface的条件
    func (h haier) wash() {
    	fmt.Println("洗刷刷")
    }
    
    // Sayer 接口
    type Sayer interface {
    	say()
    }
    
    // Mover 接口
    type Mover interface {
    	move()
    }
    
    // 接口嵌套
    type animal interface {
    	Sayer
    	Mover
    }
    type cat struct {
    	name string
    }
    
    //cat实现了两个方法,则也满足animal的接口要求
    func (c cat) say() {
    	fmt.Println("喵喵喵")
    }
    
    func (c cat) move() {
    	fmt.Println("猫会动")
    }
    
    func main() {
    	h1 := haier{}
    	var x WashingMachine = h1
    	x.dry()
    	x.wash()
    	//cat实现了嵌套里的两个接口的方法,所以也属于animal接口类型
    	var y animal = cat{name: "花花"}
    	y.move()
    	y.say()
    }
    
  • 空接口

    空接口是没有定义任何方法的接口,所以任何类型都实现了空接口。空接口类型的变量可以存储任意类型的变量。

    package main
    
    import "fmt"
    
    //空接口用interface{}表示,是一种类型,表示任意类型
    //interface关键字,interface{}空接口类型
    
    // 空接口作为函数参数,可以接受所有类型参数
    func show(a interface{}) {
    	fmt.Printf("type:%T value:%v\n", a, a)
    }
    
    func main() {
    	//空接口作为类型,可以接收所有类型
    	var m1 map[string]interface{} = make(map[string]interface{}, 16)
    	m1["name"] = "周林"
    	m1["age"] = 9000
    	m1["married"] = true
    	m1["hobby"] = [...]string{"唱", "跳", "rap"}
    	fmt.Println(m1)
    
    	show(false)
    	show(nil)
    	show(m1)
    }
    
  • 类型断言

    只有接口类型能做类型断言。

    package main
    
    import (
    	"fmt"
    )
    
    //类型断言x.(T),x为interface{}类型,T表示可能的类型,返回两个参数,第一个是转换为T类型的值,一个是判断是否正确的bool值
    func assignstring(a interface{}) {
    	str, ok := a.(string)
    	if !ok {
    		fmt.Println("wrong")
    	} else {
    		fmt.Printf("传进来的是字符串%s\n", str)
    	}
    
    }
    
    //使用switch可以断言多次进行判断
    //如果断言只用一个值接受则就是用断言类型转换后的值
    func assign2(a interface{}) {
    	switch t := a.(type) {
    	case string:
    		fmt.Printf("x is a string,value is %v\n", t)
    	case int:
    		fmt.Printf("x is a int is %v\n", t)
    	case bool:
    		fmt.Printf("x is a bool is %v\n", t)
    	default:
    		fmt.Println("unsupport type!")
    	}
    
    }
    
    func main() {
    	assignstring(100)
    	assign2("gogogogo")
    	assign2(true)
    	assign2(555)
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值