• GO:interface


    一、感受接口

    type Usb interface {
        Connect()
        Disconnect()
    }
    // 手机
    type Phone struct {}
    // 相机
    type Camera struct {}
    // 计算机
    type Computer struct {}
    // 手机实现接口所有方法
    func (p Phone) Connect() {
        fmt.Println("手机连接中...")
    }
    func (p Phone) Disconnect() {
        fmt.Println("手机断开连接中...")
    }
    // 相机实现接口所有方法
    func (c Camera) Connect() {
        fmt.Println("相机连接中...")
    }
    func (c Camera) Disconnect() {
        fmt.Println("相机断开连接中...")
    }
    // Working方法,接收一个Usb接口类型变量
    func (c Computer) Working(usb Usb) {
        // 通过接口变量来调用Connect和Disconnect方法
        usb.Connect()
        usb.Disconnect()
    }
    func main() {
        // 创建结构体实例
        phone := Phone{}
        camera := Camera{}
        computer := Computer{}
        // 关键点
        computer.Working(phone)
        computer.Working(camera)
    }
    // 输出如下
    // 手机连接中...
    // 手机断开连接中...
    // 相机连接中...
    // 相机断开连接中...
    View Code

    当传入一个phone,usb就能识别是手机,传入camera,usb就能识别是相机,并别分调用其相应的方法。这很明显就是多态呀!!!

    func (c Computer) Working(usb Usb) {
    	usb.Connect()
    	usb.Disconnect()
    }
    func main() {
    	phone := Phone{}
    	camera := Camera{}
    	computer := Computer{}
    	computer.Working(phone)
    	computer.Working(camera)
    }
    

    二、接口介绍

    interface 类型可以定义一组方法,但是这些方法不需要实现。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现了这个接口。

    语法:

    type 接口名 interface {
    	method1(参数列表) 返回值列表
    	method2(参数列表) 返回值列表
    	...
    }
    

    三、注意事项和细节

    1. 接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的实例;
    2. 接口中所有的方法都没有方法体,即只定义方法,没有实现该方法;
    3. 一个自定义类型只有实现了某个接口,才能将该自定义类型的实例赋给该接口类型;
    4. 只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型;
    5. 一个自定义类型可以实现多个接口;
    6. golang的接口不能有任何变量;
    7. 一个接口(比如 C 接口)可以继承多个别的接口(比如 A、B 接口),这时如果要实现 C 接口,也必须将 A、B 接口中的方法也实现;注意,A、B接口中不能有相同的方法,相当于 C 接口有两个相同的方法,这是不允许的;
    8. interface 类型默认是一个指针(引用类型),如果没有对 interface 初始化就使用,那么会输出 nil ;
    9. 空接口 interface{} 没有任何方法,因此所有类型都实现了空接口,即可以把任何一个变量赋给空接口
    10. 如果一个自定义类型是使用指针方式实现一个接口的,那么需要将该自定义类型的地址赋给该接口,不然会报错。
    type AInterface interface {
        Eat()
    }
    
    type Person struct {
        Name string
    }
    
    func (p Person) Eat() {
        fmt.Printf("%s正在吃饭...
    ", p.Name) // 佩奇正在吃饭...
    }
    
    func main() {
        p := Person{"佩奇"}
        var a AInterface = p // 接口可以指向一个实现了该接口的自定义类型实例
        a.Eat()
    }
    第1、3点
    type AInterface interface {
        Eat()
    }
    
    type BInterface interface {
        Sleep()
    }
    
    type Person struct {
        Name string
    }
    
    func (p Person) Eat() {
        fmt.Printf("%s正在吃饭...
    ", p.Name) // 佩奇正在吃饭...
    }
    
    func (p Person) Sleep() {
        fmt.Printf("%s正在睡觉...
    ", p.Name) // 佩奇正在睡觉...
    }
    
    func main() {
        p := Person{"佩奇"}
        var a AInterface = p
        var b BInterface = p
        a.Eat()
        b.Sleep()
    }
    第5点
    type AInterface interface {
        Eat()
    }
    
    type BInterface interface {
        Sleep()
    }
    
    type CInterface interface {
        AInterface
        BInterface
        Study()
    }
    
    type Person struct {
        Name string
    }
    
    func (p Person) Eat() {
        fmt.Printf("%s正在吃饭...
    ", p.Name) // 佩奇正在吃饭...
    }
    
    func (p Person) Sleep() {
        fmt.Printf("%s正在睡觉...
    ", p.Name) // 佩奇正在吃饭...
    }
    
    func (p Person) Study() {
        fmt.Printf("%s正在学习...
    ", p.Name) // 佩奇正在学习...
    }
    
    func main() {
        p := Person{"佩奇"}
        var c CInterface = p
        c.Eat()
        c.Sleep()
        c.Study()
    }
    第7点
    type T interface {}
    
    type Integer int
    
    func main() {
        var int1 Integer
        int2 := Integer(100)
        var t T
        t = int1
        fmt.Println(t) // 0
        t = int2
        fmt.Println(t) // 100
    }
    第9点
    type A interface {
        Eat()
    }
    
    type Person struct {
        Name string
    }
    
    // 使用 Person 指针类型实现一个接口的方法
    func (p *Person) Eat() {
        fmt.Printf("%s正在吃饭...", p.Name)
    }
    
    func main() {
        p := Person{"佩奇"}
        //var a A = p // 错误!!!因为Person类型没有实现A接口,修改如下
        var a A = &p
        a.Eat()
    }
    第10点

    四、接口最佳实践

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

    package main
    
    import (
        "fmt"
        "math/rand"
        "sort"
        "time"
    )
    
    type Student struct {
        Name string
        Score int
    }
    
    type StudentSlice []Student
    
    func (ss StudentSlice) Len() int {
        return len(ss)
    }
    // Less方法决定使用什么标准进行排序
    // 这里按成绩从小到大排序
    func (ss StudentSlice) Less(i, j int) bool {
        return ss[i].Score < ss[j].Score
    }
    func (ss StudentSlice) Swap(i, j int) {
        ss[i], ss[j] = ss[j], ss[i]
    }
    
    func main() {
        var ss StudentSlice
        rand.Seed(time.Now().UnixNano())
        for i := 0; i < 10; i++ {
            student := Student{
                Name: fmt.Sprintf("学生%d号", i),
                Score: rand.Intn(100),
            }
            ss = append(ss, student)
        }
        // 排序前的顺序
        for _, v := range ss {
            fmt.Println(v)
        }
        // 调用sort.Sort方法
        sort.Sort(ss)
        fmt.Println()
        // 排序后的顺序
        for _, v := range ss {
            fmt.Println(v)
        }
    }
    View Code

    输出结果:

    五、接口与继承的区别

    package main
    
    import "fmt"
    
    type Monkey struct {
        Name string
    }
    
    type LittleMonkey struct {
        Monkey // 继承
    }
    
    type BridAble interface {
        Flying()
    }
    type FishAble interface {
        Swimming()
    }
    
    func (m *Monkey) Climbing() {
        fmt.Printf("%s天生就会爬树...
    ", m.Name)
    }
    
    func (ls *LittleMonkey) Flying() {
        fmt.Printf("%s通过学习,会飞翔...
    ", ls.Name)
    }
    
    func (ls *LittleMonkey) Swimming() {
        fmt.Printf("%s通过学习,会游泳...
    ", ls.Name)
    }
    
    func main() {
        wk := LittleMonkey{Monkey{"小猴子"}}
        wk.Climbing()
        wk.Flying()
        wk.Swimming()
    }
    View Code

    代码小结:

    1. 当 B 结构体继承了 A 结构体,那么 B 结构体就"拥有"了 A 结构体的字段和方法,并且可以直接使用;
    2. 当 B 结构体需要扩展功能,同时不希望去破坏继承关系,则实现某个接口即可。因此可以认为:实现接口可以看做是对继承的一种补充。

    接口与继承总结:

    ①接口与继承解决的问题不同

    • 继承的价值主要在于:解决代码的复用性可维护性
    • 接口的价值主要在于:设计,设计好各种规范(方法),让其它自定义类型去实现这些方法。

    ②接口比继承更加灵活

    • 继承是 is - xx 的关系,而接口是 like - xx 的关系。为什么这样说? --> 我们不能说猴子是一条鱼,但可以说:猴子可以像鱼儿一样游泳。

    ③接口在一定程度上实现代码解耦

  • 相关阅读:
    jquery事件优化---事件委托
    2017年7月6号,总结所遇到的问题
    js日期函数
    跨域请求所遇到的错误
    ajax设置Access-Control-Allow-Origin实现跨域访问
    php提前输出响应及注意问题
    php中的日期和时间
    跨域请求json数据
    C++ 与 Visual Studio 2019 和 WSL(四)——库组件
    fpic 和 fPIC
  • 原文地址:https://www.cnblogs.com/believepd/p/10940226.html
Copyright © 2020-2023  润新知