Go接口interface
接口在底层分为接口类型和接口值,零值为nil
为什么使用接口
package main
import (
"fmt"
)
//为什么需要接口
type dog struct {
}
func (d dog) say() {
fmt.Print("汪汪汪~")
}
type cat struct {
}
func (c cat)say() {
fmt.Println("喵喵喵~")
}
//接口不管你是什么类型,他只管你要实现什么方法
//定义一个类型,一个抽象的类型,只要实现了say()这个方法的类型都可以陈革伟sayer类型
type sayer interface {
say()
}
//da的函数
func da(arg sayer) {
arg.say()//不管传进来的是什么,我都要大Ta,就要执行Ta的say方法
}
func main() {
c1:= cat{}
da(c1)
d1:=dog{}
da(d1)
}
使用值接受者实现接口和使用指针接受者实现接口的区别
package main
import "fmt"
//使用值接受者实现接口和使用指针接受者实现接口的区别
type mover interface {
move()
}
type person struct {
name string
age int8
}
//使用值接受者实现接口:不管是类型的值还是类型的指针都可以保存到接口变量中
//func (p person) move() {
// fmt.Printf("%s再跑...",p.name)
//}
//使用指针接受者实现接口:只能将类型的指针保存到接口变量中
func (p *person) move() {
fmt.Printf("%s还在跑...",p.name)
}
func main() {
var m mover
//p1 :=person{//person类型的值
// "小王子",
// 18,
//}
p2 :=&person{//person类型的指针
"小公主",
19,
}
//m=p1//?无法复制,因为p1是person类型的值没有实现mover接口
m=p2
m.move()
fmt.Println(m)
}
一个类型可以实现多个接口
package main
import "fmt"
//路由嵌套
type all interface {
mover
sayer
}
//使用值接受者实现接口和使用指针接受者实现接口的区别
type mover interface {
move()
}
type sayer interface {
say()
}
type person struct {
name string
age int8
}
//使用值接受者实现接口:不管是类型的值还是类型的指针都可以保存到接口变量中
//func (p person) move() {
// fmt.Printf("%s再跑...",p.name)
//}
//使用指针接受者实现接口:只能将类型的指针保存到接口变量中
func (p *person) move() {
fmt.Printf("%s还在跑...",p.name)
}
func (p *person) say() {
fmt.Printf("%s在叫",p.name)
}
func main() {
var m mover
//p1 :=person{//person类型的值
// "小王子",
// 18,
//}
var n sayer
p2 :=&person{//person类型的指针
"小公主",
19,
}
//m=p1//?无法复制,因为p1是person类型的值没有实现mover接口
m=p2
n=p2
m.move()
fmt.Println(m)
n.say()
var s all
s = p2//p2既实现了say方法,也实现了move方法因此可以将p2存入到接口中去
s.move()
s.say()
}
多个类型也可以实现同一个接口
package main
import (
"fmt"
)
//为什么需要接口
type dog struct {
}
func (d dog) say() {
fmt.Print("汪汪汪~")
}
type cat struct {
}
func (c cat)say() {
fmt.Println("喵喵喵~")
}
//接口不管你是什么类型,他只管你要实现什么方法
//定义一个类型,一个抽象的类型,只要实现了say()这个方法的类型都可以陈革伟sayer类型
type sayer interface {
say()
}
//da的函数
func da(arg sayer) {
arg.say()//不管传进来的是什么,我都要大Ta,就要执行Ta的say方法
}
func main() {
c1:= cat{}
da(c1)
d1:=dog{}
da(d1)
}
空接口
空接口是指没有定义的任何方法,因此任何类型都实现了空接口
空接口类型的变量可以存储任意类型的变量
import (
"fmt"
)
//空接口
//接口中没有定义任何方法值
//任意类型都实现了空接口-->空接口变量可以存储任意值
//空接口一般不需要提前定义。用到时直接使用就可以
type xxx interface {}//没必要写
//空接口的应用
//1.空接口类型作为函数的参数(例如printf函数可以打印任意类型的变量,是因为prin函数在参数类型哪里是可变长度的空接口)
//func Println(a ...interface{}) (n int, err error) {
// return Fprintln(os.Stdout, a...)
//}
//2.空接口可以作为map的value
func main() {
var x interface{}//定义x为一个空接口类型的变量,这样就可以想x中存储任意类型的变量
x= "hello"
fmt.Println(x)
x=100
fmt.Println(x)
x=true
fmt.Println(x)
var m = make(map[string]interface{},16)
m["name"]="娜扎"
m["age"]=18
m["hobby"]=[]string{"篮球","足球","双色球"}
fmt.Println(m)
}
接口值
一个接口的值(简称接口值)是有一个具体类型和具体类型的值两部分组成的。这两部分分别称为接口的动态类型和动态值
类型断言
package main
import (
"fmt"
)
//空接口
//接口中没有定义任何方法值
//任意类型都实现了空接口-->空接口变量可以存储任意值
//空接口一般不需要提前定义。用到时直接使用就可以
type xxx interface {}//没必要写
//空接口的应用
//1.空接口类型作为函数的参数(例如printf函数可以打印任意类型的变量,是因为prin函数在参数类型哪里是可变长度的空接口)
//func Println(a ...interface{}) (n int, err error) {
// return Fprintln(os.Stdout, a...)
//}
//2.空接口可以作为map的value
func main() {
var x interface{}//定义x为一个空接口类型的变量,这样就可以想x中存储任意类型的变量
x= "hello"//存入的值分为两步,存入类型和值
//fmt.Println(x)
x=100
//fmt.Println(x)
//fmt.Println(x)
//var m = make(map[string]interface{},16)
//m["name"]="娜扎"
//m["age"]=18
//m["hobby"]=[]string{"篮球","足球","双色球"}
//fmt.Println(m)
//类型断言
ret,ok:=x.(int)//猜的类型不对时、ok=false,ret=string类型的零值
if !ok{
fmt.Println("不是字符串类型")
}else {
fmt.Println("是字符串类型")
}
fmt.Println(ret)
//类型断言的另外一种写法
switch v:= x.(type) {
case string:
fmt.Printf("字符串 %v ",v)
case bool:
fmt.Printf("是布尔类型%v",v)
case int:
fmt.Printf("是int型",v)
default:
fmt.Printf("智穷了,%v",v)
}
}