目录
demo:在电脑上定义一个uSB接口,实现鼠标,u盘存储,电扇的功能
接口
在Go语言中接口(interface)是一种类型,一种抽象的类型。
interface是一组method的集合,是duck-type programming的一种体现。接口做的事情就像是定义一个协议(规则),只要一台机器有洗衣服和甩干的功能,我就称它为洗衣机。不关心属性(数据),只关心行为(方法)。
为了保护你的Go语言职业生涯,请牢记接口(interface)是一种类型。
为什么使用接口
type Cat struct{}
func (c Cat) Say() string { return "喵喵喵" }
type Dog struct{}
func (d Dog) Say() string { return "汪汪汪" }
func main() {
c := Cat{}
fmt.Println("猫:", c.Say())
d := Dog{}
fmt.Println("狗:", d.Say())
}
上面的代码中定义了猫和狗,然后它们都会叫,你会发现main函数中明显有重复的代码,如果我们后续再加上猪、青蛙等动物的话,我们的代码还会一直重复下去。那我们能不能把它们当成“能叫的动物”来处理呢?
像类似的例子在我们编程过程中会经常遇到:
比如一个网上商城可能使用支付宝、微信、银联等方式去在线支付,我们能不能把它们当成“支付方式”来处理呢?
比如三角形,四边形,圆形都能计算周长和面积,我们能不能把它们当成“图形”来处理呢?
比如销售、行政、程序员都能计算月薪,我们能不能把他们当成“员工”来处理呢?
Go语言中为了解决类似上面的问题,就设计了接口这个概念。接口区别于我们之前所有的具体类型,接口是一种抽象的类型。当你看到一个接口类型的值时,你不知道它是什么,唯一知道的是通过它的方法能做什么。
接口定义
概念: Interface类型可以定义一组方法,不需要实现,并且不能包含任何变量,称之为接口。
接口不需要显示的实现,只需要一个变量,含有接口类型中的所有方法,那么这个变量就实现了这个接口,如果一个变显含有了多个interface类型的方法,那么这个变量就实现了多个接口。
接口是一个或多个方法签名的集合。 任何类型的方法集中只要拥有该接口'对应的全部方法'签名。 就表示它 "实现" 了该接口,无须在该类型上显式声明实现了哪个接口。 这称为Structural Typing。 所谓对应方法,是指有相同名称、参数列表 (不包括参数名) 以及返回值。 当然,该类型还可以有其他方法。 接口只有方法声明,没有实现,没有数据字段。 接口可以匿名嵌入其他接口,或嵌入到结构中。 对象赋值给接口时,会发生拷贝,而接口内部存储的是指向这个复制品的指针,既无法修改复制品的状态,也无法获取指针。 只有当接口存储的类型和对象都为nil时,接口才等于nil。 接口调用不会做receiver的自动转换。 接口同样支持匿名字段方法。 接口也可实现类似OOP中的多态。 空接口可以作为任何类型数据的容器。 一个类型可实现多个接口。 接口命名习惯以 er 结尾。
每个接口由数个方法组成,接口的定义格式如下:
type 接口类型名 interface{
方法名1( 参数列表1 ) 返回值列表1
方法名2( 参数列表2 ) 返回值列表2
…
}
其中:
1.接口名:使用type将接口定义为自定义的类型名。Go语言的接口在命名时,一般会在单词后面添加er,如有写操作的接口叫Writer,有字符串功能的接口叫Stringer等。接口名最好要能突出该接口的类型含义。
2.方法名:当方法名首字母是大写且这个接口类型名首字母也是大写时,这个方法可以被接口所在的包(package)之外的代码访问。
3.参数列表、返回值列表:参数列表和返回值列表中的参数变量名可以省略。
举个例子:
type writer interface{
Write([]byte) error
}
当你看到这个接口类型的值时,你不知道它是什么,唯一知道的就是可以通过它的Write方法来做一些事情。
空接口
空接口是指没有定义任何方法的接口。因此任何类型都实现了空接口。
空接口类型的变量可以存储任意类型的变量。
package main
import "fmt"
//空接口
type Test interface
func main() {
//声明接口
var t Test
var a interface{}
var b int
a = b
fmt.Printf("a数据类型:%T\n", a)
fmt. Printf("Test数据类型:%T\n", t)
}
运行结果
a的类型:int,a的值:0
Test的数据类型:<nil>,t的值:<nil>
示例二:
package main
import "fmt"
func main() {
// 定义一个空接口x
var x interface{}
s := "pprof.cn"
x = s
fmt.Printf("type:%T value:%v\n", x, x)
i := 100
x = i
fmt.Printf("type:%T value:%v\n", x, x)
b := true
x = b
fmt.Printf("type:%T value:%v\n", x, x)
}
运行结果
type:string value:pprof.cn
type:int value:100
type:bool value:true
示例:结构体使用接口打印信息。
package main
import "fmt”
type student struct {
Name string
Age int
score float32
}
//接口定义:接口是功能的抽象
type Test interface {
Print()
}
//指针类型实现接口
func (p *Student) Print() {
fmt.Println("name: ",p.Name)
fmt.Print1n("age:", p.Age)
fmt.Println("score:", p.Score)
}
/*值类型实现接口
func (p Student)Print(){
fmt.Println("name: ",p.Name)
fmt.Println("age:", p.Age)
fmt.Println("score:", p.Score)
}
*/
func main(){
var t Test
var stu Student = Student{
Name: "zhangsan",
Age: 18,
Score:90,
}
//结构体实现接口功能t = stu值类型使用t - &stu
t.print()
}
运行结果
Name: zhangsan
Age: 18
Score:90
多态概念
package main
import "fmt"
//定义一个结构体
type Car struct {
name string
color string
}
//定义接口
type Cry interface {
call()
Sleep()
}
//使用接口
func (c *Car) call() {
fmt.Printf("name:%s\n", c.name)
fmt.Printf("color:%s\n", c.color)
}
func (c *Car) Sleep() {
fmt.Println("加油 梦想")
}
func main() {
//定义接口变量
var t Cry
var car Car = Car{
name: "audiRs7",
color: "black",
}
t = &car
t.call()
t.Sleep()
}
name:audiRs7
color:black
加油 梦想
示例二
package main
import "fmt"
//父类
type Persion struct {
Name string
Age int8
}
type Women struct {
Persion
Looks string
}
type Men struct {
Persion
Money float32
}
//定义接口
type Move interface {
Sleep()
Action()
}
func (w Women) Action() {
fmt.Printf("name:%s\n", w.Name)
fmt.Printf("Age:%d\n", w.Age)
fmt.Printf("Looks:%s\n", w.Looks)
}
func (w Women) Sleep() {
fmt.Println("正在休息")
}
func (m Men) Action() {
fmt.Printf("name:%s\n", m.Name)
fmt.Printf("Age:%d\n", m.Age)
fmt.Printf("money:%f\n", m.Money)
}
func (m Men) Sleep() {
fmt.Println("正在休息")
}
func main() {
var t Move
var wo Women
wo.Name = "zhangsan"
wo.Age = 20
wo.Looks = "漂亮"
t = wo
t.Action()
t.Sleep()
fmt.Println("-----------------")
var m Men
m.Name = "zhangsan"
m.Age = 20
m.Money = 13433545
t = m
t.Action()
t.Sleep()
}
name:zhangsan
Age:20
Looks:漂亮
正在休息
-----------------
name:zhangsan
Age:20
money:13433545.000000
正在休息
多接口的实现
示例
package main
import "fmt"
//父类
type Persion struct {
Name string
Age int8
}
type Women struct {
Persion
Looks string
}
type Men struct {
Persion
Money float32
}
//定义接口1
type Move interface {
Sleep()
}
type Move2 interface {
Action()
}
func (w Women) Action() {
fmt.Printf("name:%s\n", w.Name)
fmt.Printf("Age:%d\n", w.Age)
fmt.Printf("Looks:%s\n", w.Looks)
}
func (w Women) Sleep() {
fmt.Println("正在休息")
}
func (m Men) Action() {
fmt.Printf("name:%s\n", m.Name)
fmt.Printf("Age:%d\n", m.Age)
fmt.Printf("money:%f\n", m.Money)
}
func (m Men) Sleep() {
fmt.Println("正在休息")
}
func main() {
var t Move2
var t1 Move
var wo Women
wo.Name = "zhangsan"
wo.Age = 20
wo.Looks = "漂亮"
t = wo
t.Action()
t1 = wo
t1.Sleep()
fmt.Println("-----------------")
var m Men
m.Name = "zhangsan"
m.Age = 20
m.Money = 13433545
t = m
t.Action()
t1 = m
t1.Sleep()
}
运行结果
name:zhangsan
Age:20
Looks:漂亮
正在休息
-----------------
name:zhangsan
Age:20
money:13433545.000000
正在休息
demo
package main
import "fmt"
type Sayer interface {
say()
}
// Mover 接口
type Mover interface {
move()
}
//dog既可以实现Sayer接口,也可以实现Mover接口。
type dog struct {
name string
}
// 实现Sayer接口
func (d dog) say() {
fmt.Printf("%s会叫汪汪汪\n", d.name)
}
// 实现Mover接口
func (d dog) move() {
fmt.Printf("%s会动\n", d.name)
}
func main() {
var x Sayer
var y Mover
var a = dog{name: "旺财"}
x = a
y = a
x.say()
y.move()
}
运行结果
旺财会叫汪汪汪
旺财会动
demo:在电脑上定义一个uSB接口,实现鼠标,u盘存储,电扇的功能
package main
import "fmt"
//在电脑上定义一个uSB接口,实现鼠标,u盘存储,电扇的功能
//父类 usb
type Usb struct {
MouseName string
Uname string
FanName string
}
type USB interface {
mouse()
U()
Fan()
}
func (u Usb) mouse() {
fmt.Printf("我是鼠标,名字叫:%s\n", u.MouseName)
}
func (u Usb) U() {
fmt.Println("我是u盘\n", u.Uname)
}
func (u Usb) Fan() {
fmt.Println("我是风扇\n", u.FanName)
}
func main() {
var t USB
var us Usb
us.MouseName = "雷蛇"
us.Uname = "666"
us.FanName = "风扇"
t = us
t.mouse()
t.Fan()
t.U()
}
运行结果
我是鼠标,名字叫:雷蛇
我是风扇
风扇
我是u盘
666
系统接口的调用
示例:使用接口进行排序 结构体切片插入
go标准库
sort package - sort - pkg.go.dev
package main
import (
"fmt"
"math/rand"
"sort"
)
//定义结构体
type Student struct {
Name string
Age int
score float32
}
//定义切片
type StudentArray []Student
//定义sort接口
func (s StudentArray) Len() int {
return len(s)
}
func (s StudentArray) Less(i, j int) bool {
return s[i].Name < s[j].Name
}
func (s StudentArray) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func main() {
//切片
var Stu StudentArray
//生成10个结构体放入切片中
for i := 0; i < 10; i++ {
var stu = Student{
Name: fmt.Sprintf("stu%d:", rand.Intn(100)),
Age: rand.Intn(100),
score: rand.Float32() * 100,
}
//元素追加
Stu = append(Stu, stu)
}
//排序
sort.Sort(Stu)
//遍历
for _, v := range Stu {
fmt.Println(v)
}
}
运行结果
{stu0: 94 81.36399}
{stu25: 40 9.696952}
{stu37: 6 20.318687}
{stu47: 47 75.2573}
{stu59: 81 68.682304}
{stu62: 89 31.805817}
{stu66: 28 86.249146}
{stu74: 11 29.310184}
{stu81: 87 66.45601}
{stu88: 90 69.67192}
接口嵌套
示例:文件的读取操作
package main
import "fmt"
//定义读写接口
type Reader interface {
read()
}
type Wirter interface {
wirter()
}
//嵌套接口
type ReaderWirter interface {
Reader
Wirter
}
//定义一个结构体
type file struct {
wen string
xie string
}
//接口实现
func (f *file) read() {
fmt.Println("读的功能", f.wen)
}
func (f *file) wirter() {
fmt.Println("写的功能", f.xie)
}
//读写操作函数
func Test(rw ReaderWirter) {
rw.read()
rw.wirter()
}
func main() {
var f = file{
wen: "你真漂亮",
xie: "谢谢",
}
Test(&f)
}
运行结果
读的功能 你真漂亮
写的功能 谢谢
类型断言
作用:因为接口是一般类型,需要明确具体类型的时候就需要使用类型断言。
package main
import "fmt
func main(){
var a interface{}
var b int
a=b
//断言赋值
c := a.(int)
fmt.Printf(类型:%T\n",c)
}
运行结果
类型:int
类型判断处理
package main
import "fmt"
//类型断言
func main() {
//定义空接口
var a interface{}
//变量b
var b string
a = b
fmt.Printf("a的类型为%T,a的结构为%#v\n", a, a)
//断言处理
//var c = a.(string)
c, err := a.(int)
//类型判断
if err { //if err ==true 应该省略bool常量的比较,可以简化为err
fmt.Printf("类型为:%T,结构为%#v", c, c)
} else {
fmt.Println("不是string类型")
}
}
运行结果
a的类型为string,a的结构为""
不是string类型
断言处理
package main
import "fmt"
//断言处理
func Test(t interface{}) {
var v, err = t.(int)
if !err {
fmt.Println("这不是int类型")
return
}
v++
fmt.Println(v)
}
func main() {
Test("hello")
}
运行结果
这不是int类型
多类型判断switch type
package main
import "fmt"
//多类型断言判断
func ClassArray(item ...interface{}) {
//遍历
for i, v := range item {
//switch 。。。 type类型,只能用于switch语句中,用来判断类型
switch v.(type) {
case bool:
fmt.Printf("%d是bool类型\n", i+1)
case int:
fmt.Printf("%d是int类型\n", i+1)
case string:
fmt.Printf("%d是string类型\n", i+1)
case float32:
fmt.Printf("%d是float32类型\n", i+1)
case int64:
fmt.Printf("%d是int64类型\n", i+1)
default:
fmt.Printf("%d其他类型", i+1)
}
}
}
func main() {
ClassArray(true, "hello", "1231", "world", 133, nil)
}
运行结果
1是bool类型
2是string类型
3是string类型
4是string类型
5是int类型
6其他类型
链表使用
package main
import "fmt"
//定义节点结构体
type NodeLink struct {
//接口
data interface{}
//指向
Next *NodeLink
}
//链表结构体
type Link struct {
Head *NodeLink
Tail *NodeLink
}
//头部插入
func (n *Link) addHead(d interface{}) {
var node *NodeLink = &NodeLink{
data: d,
Next: nil,
}
if n.Head == nil && n.Tail == nil {
n.Head = node
n.Tail = node
return
}
//平移
node.Next = n.Head
n.Head = node
}
//尾部插入
func (n *Link) addTail(d interface{}) {
var node *NodeLink = &NodeLink{
data: d,
Next: nil,
}
if n.Head == nil && n.Tail == nil {
n.Head = node
n.Tail = node
return
}
//平移
n.Tail.Next = node
n.Tail = node
}
//遍历
func (no *Link) Req() {
var lp = no.Head
for lp != nil {
fmt.Println(lp)
lp = lp.Next
}
}
func main() {
//节点插入
var link Link
for i := 0; i < 10; i++ {
link.addHead(i)
}
//遍历
link.Req()
}
运行结果
&{9 0xc000004138}
&{8 0xc000004120}
&{7 0xc000004108}
&{6 0xc0000040f0}
&{5 0xc0000040d8}
&{4 0xc0000040c0}
&{3 0xc0000040a8}
&{2 0xc000004090}
&{1 0xc000004078}
&{0 <nil>}
注意:切片不可以直接赋值给空接口,只能单独每个元素赋值。
var a []int
var b[]interface
b=a //出现报错