Go语言接口
隐姓埋名4869 人气:01. 接口定义
- Interface 类型可以定义一组方法,不需要实现,并且不能包含任何的变量,称之为接口
- 接口不需要显示的实现,只需要一个变量,含有接口类型中的所有方法,那么这个变量就实现了这个接口,如果一个变量含有多个interface 类型的方法,那么这个变量就实现了多个接口
- 接口又称为动态数据类型,在进行接口使用的的时候,会将接口对位置的动态类型改为所指向的类型
- 会将动态值改成所指向类型的结构体
- 每个接口由数个方法组成,接口的定义格式如下:
其中参数列表和返回值列表中的参数变量名可以省略
type 接口类型名 interface{
方法名1( 参数列表1 ) 返回值列表1
方法名2( 参数列表2 ) 返回值列表2
…
}
自定义接口步骤
① 定义接口
② 定义结构体
③ 接口实现(绑定结构体)
④ 定义接口变量,初始化结构体,调用接口实现功能
1.1 空接口
空接口就相当于一个空指针
package main import "fmt" //定义空接口 type Test interface{} func main() { //声明接口方法1 var t Test fmt.Printf("t的类型: %T, t的值: %v\n", t, t) //声明接口方法2 var a interface{} var b int a = b fmt.Printf("a的类型: %T, a的值: %v\n", a, a) }
输出结果如下
t的类型: <nil>, t的值: <nil>
a的类型: int, a的值: 0
1.2 实现单一接口
结构体使用接口打印信息
package main import "fmt" type Student struct { Name string Age int Score float32 } //接口定义:接口是功能的抽象,不需要实现 type Test interface { Print() } //指针类型实现接口 func (p *Student) Print() { fmt.Printf("name:[%s]\n", p.Name) fmt.Printf("age:[%d]\n", p.Age) fmt.Printf("score:[%f]\n", p.Score) } //值类型实现接口 /* func (p Student) Print() { fmt.Printf("name:[%s]\n", p.Name) fmt.Printf("age:[%d]\n", p.Age) fmt.Printf("score:[%f]\n", p.Score) } */ func main() { //声明接口变量 var t Test //结构体初始化 var stu Student = Student{ Name: "zhangsan", Age: 18, Score: 90, } //把结构体赋值给接口 t = &stu //接口功能 t.Print() }
输出结果如下
name:[zhangsan]
name:[18]
name:[90.000000]
1.3 接口多方法实现
package main import "fmt" type Student struct { Name string Age int Score float32 } //接口定义:接口是功能的抽象,不需要实现 type Test interface { Print() Sleep() } //接口的实现 func (p *Student) Print() { fmt.Printf("name:[%s]\n", p.Name) fmt.Printf("age:[%d]\n", p.Age) fmt.Printf("score:[%f]\n", p.Score) } //接口中包含多个方法,如果要使用此接口就要实现接口中包含的所有方法 func (p *Student) Sleep() { fmt.Println("正在睡眠~") } func main() { //声明接口变量 var t Test //结构体初始化 var stu Student = Student{ Name: "zhangsan", Age: 18, Score: 90, } //把结构体赋值给接口 t = &stu //接口功能 t.Print() t.Sleep() }
输出结果如下
name:[zhangsan]
name:[18]
name:[90.000000]
正在睡眠~
示例,在电脑上定义一个USB接口,实现鼠标、U盘、风扇的功能
package main import "fmt" //定义电脑 type Computer struct { Brand string //品牌 Price float32 //价格 } //定义USB接口 type USB interface { mouse() store() fan() } //接口功能实现 func (c Computer) mouse() { fmt.Println("鼠标") } func (c Computer) store() { fmt.Println("U盘") } func (c Computer) fan() { fmt.Println("风扇") } func main() { //初始化结构体 var com Computer //初始化接口 var usb USB com.Brand = "thinkpad" com.Price = 5000 //接口调用 usb = com usb.mouse() usb.fan() usb.store() }
输出结果如下
鼠标
风扇
U盘
2. 多态
对于同一个接口,赋予给不同的结构体,使用相同的方法而产生出不同的操作,称之为多态。
2.1 为不同数据类型的实体提供统一的接口
package main import "fmt" //父结构体 type Persion struct { Name string Age int } //学生子结构体 type Student struct { Persion Score float32 } //教师子结构体 type Teacher struct { Persion Class int } //接口定义:接口时功能的抽象,不需要实现 type Test interface { Print() Sleep() } //学生结构体的实现 func (p *Student) Print() { fmt.Printf("name:[%s]\n", p.Name) fmt.Printf("age:[%d]\n", p.Age) fmt.Printf("Score:[%f]\n", p.Score) } //教师结构体的实现 func (p *Teacher) Print() { fmt.Printf("name:[%s]\n", p.Name) fmt.Printf("age:[%d]\n", p.Age) fmt.Printf("Class:[%d]\n", p.Class) } //接口中包含多个方法,如果要使用此接口就要实现接口中包含的所有方法 func (p *Student) Sleep() { fmt.Println("正在睡眠~") } func (p *Teacher) Sleep() { fmt.Println("正在休息~") } func main() { //声明接口变量 var t Test //学生初始化 var stu Student stu.Name = "zhangsan" stu.Age = 18 stu.Score = 90 //教师初始化 var tea Teacher tea.Name = "lisi" tea.Age = 25 tea.Class = 3 //学生接口功能调用实现 t = &stu t.Print() t.Sleep() fmt.Println("----------------------------") //教师接口功能调用实现 t = &tea t.Print() t.Sleep() }
输出结果如下
name:[zhangsan]
age:[18]
Score:[90.000000]
正在睡眠~
----------------------------
name:[lisi]
age:[25]
Class:[3]
正在休息~
2.2 多接口的实现
package main import "fmt" //接口1 type Test1 interface { Print() } //接口2 type Test2 interface { Sleep() } //结构体 type Student struct { Name string Age int Score float32 } //接口1实现 func (s Student) Print() { fmt.Printf("name:[%s]\n", s.Name) } //接口2实现 func (s Student) Sleep() { fmt.Println("正在睡眠") } func main() { //接口1变量 var t1 Test1 //接口2变量 var t2 Test2 //初始化结构体 var stu Student = Student{ Name: "zhangsan", Age: 18, Score: 90, } //调用接口实现功能 t1 = stu t1.Print() t2 = stu t2.Sleep() }
输出结果如下
name:[zhangsan]
正在睡眠
3. 系统接口调用
示例
使用接口进行排序
package main import ( "fmt" "math/rand" "sort" ) //结构体 type Student struct { Name string Age int Score float32 } //切片 type StudentArray []Student //go语言提供了sort 接口。使用接口里的方法即可 //实现sort接口 func (sa StudentArray) Len() int { return len(sa) } //获取切片长度 func (sa StudentArray) Less(i, j int) bool { return sa[i].Name > sa[j].Name } //两数比大小 func (sa StudentArray) Swap(i, j int) { sa[i], sa[j] = sa[j], sa[i] } //两数交换 func main() { //Student 切片 var stus StudentArray //生成10个结构体,放入切片中 for i := 0; i < 10; i++ { var stu Student = Student{ Name: fmt.Sprintf("stu%d", rand.Intn(100)), Age: rand.Intn(120), Score: rand.Float32() * 100, } //结构体元素存入到切片中 stus = append(stus, stu) } //遍历 for _, v := range stus { fmt.Println(v) } fmt.Println("--------------------------") //排序 sort.Sort(stus) //遍历 for _, v := range stus { fmt.Println(v) } }
4. 接口嵌套
示例:
文件读写测试
package main import "fmt" //读取的接口 type Reader interface { Read() } //写入的接口 type Writer interface { Writer() } //接口的嵌套 type ReadWriter interface { Reader Writer } //文件结构体 type File struct{} //实现Reader接口 func (f *File) Read() { fmt.Println("文件读取") } //实现Writer接口 func (f *File) Writer() { fmt.Println("文件写入") } //定义读写操作函数 func Test(rw ReadWriter) { //rw为接口变量 rw.Read() //使用读写的方法 rw.Writer() } func main() { var f File //定义结构体,初始化文件 Test(&f) }
输出结果如下
文件读取
文件写入
5. 类型断言
作用:因为接口是一般类型,需要明确具体类型的时候就需要使用类型断言
示例
package main import "fmt" func main() { //定义空接口 var a interface{} var b int a = b //a为int类型 //断言赋值 fmt.Printf("a= %v, 类型: %T\n", a, a) c := a.(int) fmt.Printf("c= %v, 类型: %T\n", c, c) }
输出结果如下
a= 0, 类型: int
c= 0, 类型: int
5.1 断言判断
package main import "fmt" func main() { //定义空接口 var a interface{} var b string a = b //a为int类型 //断言赋值 fmt.Printf("a= %v, 类型: %T\n", a, a) c, err := a.(int) if err { fmt.Printf("c= %v, 类型: %T\n", c, c) } else { fmt.Println("不是int类型") } }
输出结果如下
a= , 类型: string
不是int类型
package main import "fmt" func Test(t interface{}) { //转换类型判断 v, err := t.(int) if !err { fmt.Println("type is not int") return } v++ fmt.Println(v) } func main() { a := "张三" Test(a) }
输出结果如下
type is not int
5.2 多类型判断
package main import "fmt" func classifier(items ...interface{}) { //遍历复杂集合 for i, v := range items { //变量.(type)职能作用在switch语句中,专门用于判断类型 switch v.(type) { case bool: fmt.Printf("第 %d 个数据类型是 bool\n", i) case int, int32, int64: fmt.Printf("第 %d 个数据类型是 int\n", i) case float32, float64: fmt.Printf("第 %d 个数据类型是 float\n", i) case string: fmt.Printf("第 %d 个数据类型是 string\n", i) default: fmt.Printf("第 %d 个数据类型是其他类型\n", i) } } } func main() { //传入多种类型参数 classifier("张三", 3.14, true, 80, nil) }
输出结果如下
第 0 个数据类型是 string
第 1 个数据类型是 float
第 2 个数据类型是 bool
第 3 个数据类型是 int
第 4 个数据类型是其他类型
6. 使用接口实现链表插入
package main import "fmt" //节点结构体 type LinkNode struct { data interface{} next *LinkNode } //链表结构体 type Link struct { head *LinkNode tail *LinkNode } //从头部插入 func (p *Link) InsertHead(data interface{}) { node := &LinkNode{ data: data, next: nil, } //判断是否为空链表 if p.head == nil && p.tail == nil { p.head = node p.tail = node return } //当前节点的next是原头部节点 node.next = p.head //更新头部 p.head = node } //从尾部插入 func (p *Link) InsertTail(data interface{}) { node := &LinkNode{ data: data, next: nil, } //判断是否为空链表 if p.head == nil && p.tail == nil { p.head = node p.tail = node return } //原尾部节点的next是当前节点 p.tail.next = node //更新尾部 p.tail = node } //遍历方法 func (p *Link) Req() { lp := p.head for lp != nil { fmt.Println(lp) lp = lp.next } } func main() { //定义链表 var intLink Link for i := 0; i < 10; i++ { //intLink.InsertHead(i) intLink.InsertTail(i) } intLink.Req() }
输出结果如下
&{0 0xc000096078}
&{1 0xc000096090}
&{2 0xc0000960a8}
&{3 0xc0000960c0}
&{4 0xc0000960d8}
&{5 0xc0000960f0}
&{6 0xc000096108}
&{7 0xc000096120}
&{8 0xc000096138}
&{9 <nil>}
加载全部内容