GO语言使用之面向对象编程(7)接口

一、为什么需要接口

在Golang中 多态特性主要是通过接口来体现的。

二、基本介绍

interface类型可以定义一组方法,但是这些不需要实现。并且interface不能包含任何变量。到某个自定义类型(比如结构体Phone)要使用的时候,在根据具体情况把这些方法写出来(实现)。

三、基本语法

type 接口名 interface{

        method1(参数列表) 返回值列表
        method2(参数列表) 返回值列表
        …
}

实现接口所有方法:

func (t 自定义类型) method1(参数列表) 返回值列表 {
        //方法实现
}
func (t 自定义类型) method2(参数列表) 返回值列表 {
        //方法实现
}
//.... 

说明:
1) 接口里的所有方法都没有方法体,即接口的方法都是没有实现的方法。接口体现了程序设计的多态和高内聚低偶合的思想。
2) Golang中的接口,不需要显式的实现。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此,Golang中没有implement这样的关键字

四、快速入门案例

type camputer struct{

}
type phone struct{
    name string
    price float64
}
type camera struct{
    name string
    price float64
}

type Usb interface {
    charging()
    boot()
    shutdown()
}
//实现接口
func (p phone) charging(){
    fmt.Printf("%s手机开始充电。。。。\n",p.name)
}
func (p phone) boot(){
    fmt.Printf("%s手机正在开机。。。。\n",p.name)
}
func (p phone) shutdown(){
    fmt.Printf("%s手机关机了。。。。\n",p.name)
}
func (c camera) charging(){
    fmt.Printf("%s相机开始充电。。。。\n",c.name)
}
func (c camera) boot(){
    fmt.Printf("%s相机正在开机。。。。\n",c.name)
}
func (c camera) shutdown(){
    fmt.Printf("%s相机关机了。。。。\n",c.name)
}

func (c camputer) working(usb Usb)  {
    usb.boot()
    usb.shutdown()
    usb.charging()
}

func InterfaceDemo()  {
    p := phone{"小米",6000}
    c := camera{"尼康",20000}
    cap := camputer{}
    cap.working(p)
    cap.working(c)

}

五、使用细节和注意事项

1、 接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例)

type student struct{}

type action interface{
    sport()

}
func (s student) sport()  {

}
// 1、接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例)
func DetailsDemo1(){

        var a action
        fmt.Println("a=",a)
        var s student
        a=s
        fmt.Println("s=",s)
}

2、接口中所有的方法都没有方法体,即都是没有实现的方法。
3、 在Golang中,一个自定义类型需要将某个接口的所有方法都实现,我们说这个自定义类型实现了该接口。

// 3、在Golang中,一个自定义类型需要将某个接口的所有方法都实现,我们说这个自定义类型实现了该接口。
type student1 struct{}

type action1 interface{
    // a int
    sport()
    draw()
}
func (s student1) sport()  {

}
func DetailsDemo2(){

    var a action1
    fmt.Println("a=",a)
    var s student1
    // 如果没有将接口的所有方法实现,会出现恐慌
    // a=s
    fmt.Println("s=",s)
}

4、 一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)赋给接口类型。

// 4、一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)赋给接口类型。 
func DetailsDemo3(){
        var a action1
        fmt.Println("a=",a)
        var s student
        // a=s //stuent没有实现action1下方法,会出现恐慌
        fmt.Println("s=",s)
}

5、只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型。

// 5、只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型。
type integer int
func (i integer) sport()  {

}
func DetailsDemo4(){
        var a action
        fmt.Println("a=",a)
        var i integer
        a=i
        fmt.Println("a=",a)
}

6、 接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例)
7、 接口中所有的方法都没有方法体,即都是没有实现的方法。

// 7、Golang接口中不能有任何变量
type action2 interface{
    sport()
    // age integer
}

8、 一个接口(比如A接口)可以继承多个别的接口(比如B,C接口),这时如果要实现A接口,也必须将B,C接口的方法也全部实现。

// 8、一个接口(比如A接口)可以继承多个别的接口(比如B,C接口),这时如果要实现A接口,也必须将B,C接口的方法也全部实现。
type AInter interface {
    sayOk1()
}

type BInter interface {
    sayOk2()
    // sayOk1() //继承多个接口时,每个接口的方法不能重复
}

type CInter interface {
    AInter
    BInter
    sayOk3()
}

type Monster struct {

}

//让Monster 实现 CInter
func (m Monster) sayOk1() {
    fmt.Println("sayOk1()")
}

func (m Monster) sayOk2() {
    fmt.Println("sayOk2()")
}

func (m Monster) sayOk3() {
    fmt.Println("sayOk3()")
}

func DetailsDemo6(){    

    var monster Monster
    var c CInter
    c = monster
    fmt.Println("c=", c)

    var bInter BInter
    bInter = monster
    fmt.Println("bInter=", bInter)  
}

9、 一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)赋给接口类型。

10、 只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型。
11、 interface类型默认是一个指针(引用类型),如果没有对interface初始化就使用,那么会输出nil

// 9、interface类型默认是一个指针(引用类型),如果没有对interface初始化就使用,那么会输出nil 
func DetailsDemo7(){
    var c CInter
    fmt.Println("c=", c)
}

12、 空接口interface{} 没有任何方法,所以所有类型都实现了空接口【案例演示】

// 10、空接口interface{} 没有任何方法,所以所有类型都实现了空接口
func DetailsDemo8(){

    var m interface {}
    num1 := 10
    num2 := 12.00
    num3 := true
    num4 := "sjdskj"
    //空接口interface{}可以接受任何类型
    m = num1
    fmt.Println(m)
    m = num2
    fmt.Println(m)
    m = num3
    fmt.Println(m)
    m = num4
    fmt.Println(m)
}

完整代码如下:

package utils

import (
    "fmt"
)

type student struct{}

type action interface{
    sport()

}
func (s student) sport()  {

}
// 1、接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例)
func DetailsDemo1(){

        var a action
        fmt.Println("a=",a)
        var s student
        a=s
        fmt.Println("s=",s)
}
// 2、接口中所有的方法都没有方法体,即都是没有实现的方法。
// 3、在Golang中,一个自定义类型需要将某个接口的所有方法都实现,我们说这个自定义类型实现了该接口。
type student1 struct{}

type action1 interface{
    // a int
    sport()
    draw()
}
func (s student1) sport()  {

}
func DetailsDemo2(){

    var a action1
    fmt.Println("a=",a)
    var s student1
    // 如果没有将接口的所有方法实现,会出现恐慌
    // a=s
    fmt.Println("s=",s)
}
// 4、一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)赋给接口类型。 
func DetailsDemo3(){
        var a action1
        fmt.Println("a=",a)
        var s student
        // a=s //stuent没有实现action1下方法,会出现恐慌
        fmt.Println("s=",s)
}
// 5、只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型。
type integer int
func (i integer) sport()  {

}
func DetailsDemo4(){
        var a action
        fmt.Println("a=",a)
        var i integer
        a=i
        fmt.Println("a=",a)
}
// 6、一个自定义类型可以实现多个接口 
func DetailsDemo5(){}
// 7、Golang接口中不能有任何变量
type action2 interface{
    sport()
    // age integer
}
// 8、一个接口(比如A接口)可以继承多个别的接口(比如B,C接口),这时如果要实现A接口,也必须将B,C接口的方法也全部实现。
type AInter interface {
    sayOk1()
}

type BInter interface {
    sayOk2()
    // sayOk1() //继承多个接口时,每个接口的方法不能重复
}

type CInter interface {
    AInter
    BInter
    sayOk3()
}

type Monster struct {

}

//让Monster 实现 CInter
func (m Monster) sayOk1() {
    fmt.Println("sayOk1()")
}

func (m Monster) sayOk2() {
    fmt.Println("sayOk2()")
}

func (m Monster) sayOk3() {
    fmt.Println("sayOk3()")
}

func DetailsDemo6(){    

    var monster Monster
    var c CInter
    c = monster
    fmt.Println("c=", c)

    var bInter BInter
    bInter = monster
    fmt.Println("bInter=", bInter)  
}
// 9、interface类型默认是一个指针(引用类型),如果没有对interface初始化就使用,那么会输出nil 
func DetailsDemo7(){
    var c CInter
    fmt.Println("c=", c)
}
// 10、空接口interface{} 没有任何方法,所以所有类型都实现了空接口
func DetailsDemo8(){

    var m interface {}
    num1 := 10
    num2 := 12.00
    num3 := true
    num4 := "sjdskj"
    //空接口interface{}可以接受任何类型
    m = num1
    fmt.Println(m)
    m = num2
    fmt.Println(m)
    m = num3
    fmt.Println(m)
    m = num4
    fmt.Println(m)
}

六、接口最佳实践

实现对Hero结构体切片的排序: sort.Sort(data Interface)

/*
实现对Hero结构体切片的排序: sort.Sort(data Interface)
根据age大小排序
分析
实现原理 sort.Sort(data Interface)
 1、定义结构体 heros,并添加字段 name age
 2、自定义 heros切片类型 HeroSlice
 3、HeroSlice实现len方法,确定切片长度
 4、HeroSlice实现less方法,确定切片排序顺序
 5、HeroSlice实现swap方法,进行数据交换操作
 6、调用。
*/
type heros struct{
    name string 
    age int
}

type HeroSlice []heros

func (h HeroSlice)Len() int {

    return len(h)
}
func (h HeroSlice)Less(i,j int) bool {

    return h[i].age < h[j].age
}
func (h HeroSlice)Swap(i,j int)  {

    //传统写法
    t := h[i]
    h[i] = h[j]
    h[j] = t
    //还有一个简洁的写法
    //hs[i], hs[j] = hs[j], hs[i]

}

func SortDemo(){

    var heroSlice  HeroSlice
    for i := 0; i < 10; i++ {
        hero := heros{
            name :  fmt.Sprintf("梁山英雄%d",rand.Intn(100)),
            age : rand.Intn(100),
        }
        heroSlice = append(heroSlice,hero)
    }
    fmt.Println("heroSlice",heroSlice)
    sort.Sort(heroSlice)
    fmt.Println("heroSlice",heroSlice)
}

猜你喜欢

转载自blog.csdn.net/TDCQZD/article/details/81712660