接口在golang中使用的特别多,在此加以简单的总结:
golang接口使用说明:
(1)空接口(没有任何方法的接口)可以看成是万能数据类型,可以接收任意类型的数据;如果是包含方法的接口,给该接口赋值,对应的值对象需要实现该接口的所有方法才可以。
(2)接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例)
(3)接口中的所有方法都没有方法体,即都是没有实现的方法。
(4)在golang中,一个自定义类型需要将该接口对应的方法都实现,才能说该类型实现了该接口。
(5)只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型。
(6)一个自定义类型,可以同时实现多个接口。(如可以同时实现 A接口 B接口)
(7)若两个接口包含一样的方法,一个自定义类型实现了所有的方法,则该类型实现了这两个接口。接口的实现主要是通过方法来标记,而不是接口名称。
(8)接口类型默认是一个指针(引用类型),如果没有初始化就使用,就会输出nil。
(9)golang接口中,不能包含任意变量。
package main
import "fmt"
type USB interface {
working()
stop()
}
type USB1 interface {
working()
stop()
}
//定义Phone对象
type Phone struct {
}
//定义Cameron对象
type Cameron struct {
}
//定义Computer对象
type Computer struct {
}
//分别让两个对象实现USB的方法
func (p Phone) working() {
fmt.Println("手机开始工作。。。")
}
func (p Phone) stop() {
fmt.Println("手机停止工作")
}
func (c Cameron) working() {
fmt.Println("照相机开始工作。。。")
}
func (c Cameron) stop() {
fmt.Println("照相机停止工作")
}
func (c Computer) work(usb USB) { //具有相同接口的对象(struct)都可以作为函数参数(包含多态、高内聚低耦合的思想)
usb.working() //根据上下文判断是Cameron 还是 phone,实现了多态
usb.stop()
}
//自定义类型的变量 都可以实现接口,不一定是struct
type MyInt int
func (i MyInt) working() {
fmt.Println("自定义类型的 working() 方法")
}
func (i MyInt) stop() {
fmt.Println("自定义类型的 stop() 方法")
}
func main() {
c := Computer{}
ca := Cameron{}
ph := Phone{}
c.work(ca) //由于Cameron实现了USB的接口,所以类型可以和USB进行匹配
c.work(ph) //由于phone实现了USB的接口,所以类型可以和USB进行匹配
fmt.Println("------------")
var usb USB
var myInt MyInt
usb = myInt //赋值给接口(包含方法),myInt需要实现该接口的所有方法。
usb.stop()
myInt.working()
}
/*
特别说明: golang中实现接口不需要显示来实现(Java中通过关键字,golang中接口对应的方法来实现)
如程序所示,对象通过 working()、stop()方法的实现,实现了接口USB、USB1.所以,接口与接口的方法相关,与接口名称无关。
如果要实现接口,就要实现接口里的所有方法。
*/
案例:
使用sort包下的Sort对复杂结构类型的数据进行排序:
该方法的参数为:interface类型,如果要进行排序,需要按照对应的参数传值。对应的interface参数结构如下:
此接口是包含方法的接口,非空接口。传递的参数需要实现3个方法,
// Len方法返回集合中的元素个数
Len() int
// Less方法报告索引i的元素是否比索引j的元素小
Less(i, j int) bool
// Swap方法交换索引i和j的两个元素
Swap(i, j int)
特别说明:要实现接口必须为自定义类型(type XX 数据类型,结构体也可以看成是一种自定义类型)。
package main
import (
"fmt"
"math/rand"
"sort"
"strconv"
"time"
)
type Student struct {
Name string
Age int
Score int
}
//var MyData []Student
type Mydata []Student // 注意:是自定义类型 Mydata 实现接口对应的方法
func (s *Mydata) Len() int {
return len(*s) Len方法返回集合中(需要排序集合)的元素个数
}
func (s *Mydata)Less(i, j int) bool {
return (*s)[i].Score>(*s)[j].Score //依据什么排序 ( > 降序, < 升序)
}
func (s *Mydata) Swap(i, j int) {
//交换那些数据
(*s)[i].Score,(*s)[j].Score=(*s)[j].Score,(*s)[i].Score
(*s)[i].Name,(*s)[j].Name=(*s)[j].Name,(*s)[i].Name
(*s)[i].Age,(*s)[j].Age=(*s)[j].Age,(*s)[i].Age
}
func main() {
var studentInfor Mydata
studentInfor=make([]Student,0)
rand.Seed(time.Now().Unix())
for i:=0;i<10;i++{
name:="jiangzhou"+strconv.Itoa(i)
score:=rand.Intn(100)
age:=rand.Intn(5)+20
stu:=Student{Name:name,Age:age,Score:score}
studentInfor=append(studentInfor,stu)
}
fmt.Println("排序之前的数据为:")
for _,v:=range studentInfor{
fmt.Printf("姓名:%s, age:%d, socre:%d\n",v.Name,v.Age,v.Score)
}
//调用goland sort包下的Sort方法,该方法接收interface类型参数,需要实现对应的3个方法
/*
type Interface interface {
// Len方法返回集合中的元素个数
Len() int
// Less方法报告索引i的元素是否比索引j的元素小
Less(i, j int) bool
// Swap方法交换索引i和j的两个元素
Swap(i, j int)
}
*/
sort.Sort(&studentInfor)
fmt.Println("\n排序之后的数据为:")
for _,v:=range studentInfor{
fmt.Printf("姓名:%s, age:%d, socre:%d\n",v.Name,v.Age,v.Score)
}
}
实现接口 与 继承的 区别
(1)当A结构体继承了B结构体,则A结构体就自动拥有了B结构体的方法和字段,并且可以直接使用。
(2)当A接口需要扩展功能,同时不希望去破坏继承关系时,则可以去实现某一个接口即可。因此可以认为:实现接口是对继承机制的补充。
实现接口可以看做是对 继承的一种补充
有如下需求:如果要让足球运动员、大学生都要掌握英语技能,可以采用2种方法:(1)足球运动员绑定一个英语方法,大学生绑定一个英语方法。(2)写一个英语技能的接口,足球运动员、大学生实现此接口。很显然方法2保证了实现方法(技能要求)的一致性。
。