接口( interface ) ,在 Golang 中多态特性主要是通过接口来体现的
- package main
-
- import(
- "fmt"
- )
-
- // 声明一个接口
- type Usb interface {
- //声明了两个没有实现的方法
- Start()
- Stop()
- }
-
- //声明一个结构体,实现Usb方法
- type Phone struct{
-
- }
-
- func (p Phone) Start() {
- fmt.Println("手机开始工作...")
- }
- func (p Phone) Stop() {
- fmt.Println("手机停止工作...")
- }
-
- //相机实现Usb方法
- type Camera struct{
-
- }
-
- func (c Camera) Start() {
- fmt.Println("相机开始工作...")
- }
- func (c Camera) Stop() {
- fmt.Println("相机停止工作...")
- }
-
- //计算机
- type Computer struct{
-
- }
- //编写一个方法Working, 接收一个Usb接口类型变量
- //实现了Usb接口(就是指实现了Usb接口声明的所有方法)
- func (c Computer) Working(usb Usb) {
- //通过Usb接口变量来调用Start,Stop方法
- usb.Start()
- usb.Stop()
- }
-
- func main() {
- //先创建结构体变量
- computer := Computer{}
- phone := Phone{}
- camera := Camera{}
-
- //关键点
- computer.Working(phone)
- computer.Working(camera)
- }
- 手机开始工作...
- 手机停止工作...
- 相机开始工作...
- 相机停止工作...
interface 类型可以定义一组方法,但是这些不需要实现,并且 interfaoe 不能包含任何变量,到某个自定义类型(比如结构体 Phone )要使用的时候,再根据具体情况把这些方法写出来(实现)
type 接口名 interface {
method1(参数列表) 返回值列表
method2(参数列表) 返回值列表
}
实现接口的方法:
function (t 自定义类型) method1(参数列表) 返回值列表{
//方法实现
}
function (t 自定义类型) method2(参数列表) 返回值列表{
//方法实现
}
(1).接口里的所有方法都没有方法体,即接口的方法都是没有实现的方法。接口体现了程序设计的多态和高内聚低偶合的思想
(2 ). go中的接口,不需要显式的实现,只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此, Golang 中没有implement 这样的关键字
应用场景
(1).接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例)
- package main
-
- import(
- "fmt"
- )
-
- type AInterface interface{
- Say()
- }
-
- type Student struct{
- Name string
- }
- func (stu Student) Say(){
- fmt.Println("Stu Say()")
- }
-
- func main() {
- var stu Student //结构体变量,实现了Say(),也就实现了AInterface接口
- var a AInterface = stu
- a.Say()
- }
(2).接口中的所有的方法都没有方法体,即都没有实现的方法
(3).在go中,一个自定义类型需要将某个接口的所有方法都实现,才会说这个自定义类型实现了该接口
(4).一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)赋给接口类型
(5 ).只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型
- package main
-
- import(
- "fmt"
- )
- type integer int
- func (i integer) Say() {
- fmt.Println("i integer, i=", i)
- }
- func main() {
- var i integer = 10
- var b AInterface = i
- b.Say()//i integer, i= 10
- }
(6).一个自定义类型可以实现多个接口
- package main
-
- import(
- "fmt"
- )
-
- type AInterface interface{
- Say()
- }
- type BInterface interface{
- Hello()
- }
-
- type Monster struct{
-
- }
- func (m Monster) Say() {
- fmt.Println("Monster Say()")
- }
- func (m Monster) Hello() {
- fmt.Println("Monster Hello()")
- }
- func main() {
- //Monster实现了AInterface,BInterface
- var monster Monster
- var a1 AInterface = monster
- var b1 BInterface = monster
- a1.Say()
- b1.Hello()
- }
(7).go接口不能有任何变量
(8).一个接口(比如A接口 )可以继承多个别的接口(比如 B , C 接口),这时如果要实现A接口,也必须将 B ,C 接口的方法也全部实现
- package main
-
- import(
- "fmt"
- )
-
- type BInterface interface{
- test01()
- }
- type CInterface interface{
- test02()
- }
- type AInterface interface{
- BInterface
- CInterface
- test03()
- }
-
- //如果需要实现AInterface,就需要把BInterface,CInterface额方法都实现
- type Stu struct{
-
- }
- func (stu Stu) test01() {
-
- }
- func (stu Stu) test02() {
-
- }
- func (stu Stu) test03() {
-
- }
-
- func main() {
- var stu Stu
- var a AInterface = stu
- a.test01()
- }
(9).interface 类型默认是一个指针,如果没有对interface 初始化就使用,那么会输出nil
(10).空接口interface{}没有任何方法,所有所有类型都实现了空接口
- package main
-
- import(
- "fmt"
- )
-
- //空接口
- type T interface{
-
- }
- func main() {
- var t T = stu //ok
- fmt.Println(t) //{}
-
- var t2 interface{} = stu
- fmt.Println(t2) //{}
- var num float64 = 2.33
- t2 = num
- fmt.Println(t2)// 2.33
- }
实现对Hero结构体切片的排序:sort.Sort(data.Interface)
- package main
-
- import (
- "fmt"
- "sort"
- "math/rand"
- )
-
- //实现对Hero结构体切片的排序:sort.Sort(data interface)
- //1.声明一个Here结构体
- type Hero struct {
- Name string
- Age int
- }
-
- //2.声明一个Here结构体切片
- type HeroSlice []Hero
-
- //3.实现接口Interface接口
- // func Sort(data Interface)
- /*
- type Interface interface {
- // Len方法返回集合中的元素个数
- Len() int
- // Less方法报告索引i的元素是否比索引j的元素小
- Less(i, j int) bool
- // Swap方法交换索引i和j的两个元素
- Swap(i, j int)
- }
- */
- func (hs HeroSlice) Len() int {
- return len(hs)
- }
- //Less就是决定你使用什么标准进行排序
- //1. 按照Here的年龄从小到大排序
- //2.修改成对名字进行排序
- func (hs HeroSlice) Less(i, j int) bool {
- // 1. 按照Here的年龄从小到大排序
- // return hs[i].Age < hs[j].Age //升序
- // 2.修改成对名字进行排序
- return hs[i].Name < hs[j].Name //升序
- }
- func (hs HeroSlice) Swap(i, j int) {
- //交换
- // temp := hs[i]
- // hs[i] = hs[j]
- // hs[j] = temp
- // 上面的三句等价于下面的一句
- hs[i], hs[j] = hs[j], hs[i]
- }
-
- func main() {
- //先定义一个数组/切片
- var intSlice = []int{12, -1, 4, 2, 15}
- //要求对intSlice切片进行排序
- //1.冒泡排序
- //2.使用系统提供的方法
- sort.Ints(intSlice)
- fmt.Println(intSlice)
-
- //对结构体进行排序
- //1.冒泡排序
- //2.也可以使用系统提供的方法
-
- //对结构体切片进行排序
- var heroes HeroSlice
- for i := 0; i < 10; i++ {
- hero := Hero {
- Name : fmt.Sprintf("英雄%d", rand.Intn(100)),
- Age : rand.Intn(100),
- }
- //将hero append 到heroes切片
- heroes = append(heroes, hero)
- }
-
- //排序前的顺序
- for _, v := range heroes {
- fmt.Println(v)
- }
- //调用sort.Sort
- sort.Sort(heroes)
-
- //排序后的顺序
- fmt.Println("排序后")
- for _, v := range heroes {
- fmt.Println(v)
- }
- }
实现对Student结构体切片按照成绩升序进行排序
- package main
-
- import (
- "fmt"
- "math/rand"
- "sort"
- )
-
- //实现对Student结构体切片按照成绩升序进行排序
- //1.声明一个Student结构体
- type Student struct{
- Name string
- Age int
- Score float64
- }
-
- //2.声明一个Student切片
- type StuSlice []Student
-
- //3.实现接口Interface接口
- // func Sort(data Interface)
- /*
- type Interface interface {
- // Len方法返回集合中的元素个数
- Len() int
- // Less方法报告索引i的元素是否比索引j的元素小
- Less(i, j int) bool
- // Swap方法交换索引i和j的两个元素
- Swap(i, j int)
- }
- */
- func (stu StuSlice) Len() int {
- return len(stu)
- }
- func (stu StuSlice)Less(i, j int) bool {
- return stu[i].Score < stu[j].Score
- }
- func (stu StuSlice) Swap(i, j int) {
- stu[i], stu[j] = stu[j], stu[i]
- }
-
- func main() {
- //创建一个Student切片实例
- var stues StuSlice
- for i := 0; i <=10 ; i++ {
- stu := Student{
- Name : fmt.Sprintf("学生%v", rand.Intn(100)),
- Age : rand.Intn(100),
- Score : float64(rand.Intn(100)),
- }
- //把stu append 到stues结构体实例变量中
- stues = append(stues, stu)
- }
-
- //排序前数据
- for _,v := range stues {
- fmt.Println(v)
- }
- //排序后数据
- fmt.Println("排序后数据")
- sort.Sort(stues)
- for _,v := range stues {
- fmt.Println(v)
- }
- }
- package main
-
- import(
- "fmt"
- )
-
- //声明一个鸟儿接口
- type BridAble interface {
- Flying()
- }
- //声明一个鱼儿接口
- type FishAble interface {
- Swimming()
- }
-
- //Monkey
- type Monkey struct{
- Name string
- }
-
- func (this *Monkey) climbing() {
- fmt.Println(this.Name, "会爬树")
- }
-
- //LittleMonkey结构体
- type LittleMonkey struct{
- Monkey // 继承
- }
-
- //让LittleMonkey实现BridAble.Flying
- func (this *LittleMonkey) Flying() {
- fmt.Println(this.Name, "通过学习,学会了飞翔")
- }
- //让LittleMonkey实现FishAble.Swimming
- func (this *LittleMonkey) Swimming() {
- fmt.Println(this.Name, "通过学习,学会了游泳")
- }
- func main() {
- //创建一个LitteMonkey实例
- littleMonkey := LittleMonkey{
- Monkey {
- Name : "猴子1",
- },
- }
- littleMonkey.climbing()
- littleMonkey.Flying()
- littleMonkey.Swimming()
- }
对上面代码的小结 :
(1).当 A 结构体继承了 B 结构体,那么 A 结构就自动的继承了 B 结构体的字段和方法,并且可以直接使用
(2 ).当 A 结构体需要扩展功能同时不希望去破坏继承关系,则可以去实现某个接口即可,因此可以认为:实现接口是对继承机制的补充
接口和继承解决的解决的问题不同
继承的价值主要在于:解决代码的复用性和可维护性
接口的价值主要在于:设计,设计好各种规范(方法),让其它自定义类型去实现这些方法
接口比继承更加灵活 Person Student , BirdAble LitdeMonkev
接口比继承更加灵活,继承是满足is-a的关系,而接口只需满足 like - a的关系
接口在一定程度上实现代码解藕