zoukankan      html  css  js  c++  java
  • 7.1 Go interface

    7.1 Go interface

    雨痕-Go语言笔记

    接口采用了duck type方式,在程序设计中是动态类型的一种风格
    `当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。`
    
    空接口类型interface{},类似于OOP的system.Object,可以接收任意类型。
    准备交互的双方,共同遵守实现约定的规则,使得无须知道对方身份的情况下进行协作。
    接口要实现的是做什么,而不关心怎么做,谁来做。
    
    可以先实现类型,而后再抽象出所需接口。称作非侵入式设计。
    

    概念

    Go语言的主要设计者之一罗布·派克(Rob Pike)曾经说过,如果只能选择一个Go语言的特 性移植到其他语言中,他会选择接口

    接口在Go语言有着至关重要的地位。如果说goroutinechannel是支撑起Go语言的并发模型 的基石,让Go语言在如今集群化多核化的时代成为一道极为亮丽的风景,那么接口是Go语言 整个类型系统的基石,让Go语言在基础编程哲学的探索上达到前所未有的高度。

    Go语言在编程哲学上是变革派,而不是改良派。这不是因为Go语言有goroutine和channel, 而更重要的是因为Go语言的类型系统,更是因为Go语言的接口。Go语言的编程哲学因为有接口 而趋近完美。

    接口只有方法声明,没有实现,也没有数据字段。
    接口可以匿名嵌入到其他接口。
    对象赋值给接口时,会发生拷贝。
    只有当接口存储的类型和对象都是nil时,接口等于nil。
    空接口可以接收任意的数据类型。
    一个类型可以实现多个接口。
    接口变量名习惯以 er 结尾。
    

    接口类型是对其它类型行为的抽象和概括,接口类型不会和特定的实现细节绑定。
    Go接口独特在它是隐式实现的,这是指:一个结构体只要实现了接口要求的所有方法,我们就说这个结构体实现了该接口。
    

    接口在现实世界也是有真实场景的,如同笔记本上都有USB插口,且不用担心这个插槽是为手机U盘平板哪一个准备的,因为笔记本的usb插槽和各种设备的厂家统一了USB的插槽规范。


    1.2. 接口语法

    type 接口名 interface {
        method1(参数列表)返回值列表
        method2(参数列表)返回值列表
    }
    
    interface类型可以定义一组方法,且不需要实现这些方法!并且interface不能有任何变量。
    只要有一个变量类型,含有接口中的所有方法,就说这个变量类型实现了这个接口。
    

    Go多态与接口

    package main
    
    import "fmt"
    
    //定义一个Usb接口,且定义Usb功能方法
    type Usb interface {
        Start()
        Stop()
    }
    
    type Phone struct {
        Name  string
        Price int
    }
    
    //让手机Phone实现Usb接口的方法
    func (p Phone) Start() {
        fmt.Println("手机已连接USB,开始工作")
    }
    
    //必须实现接口所有的方法,少一个都报错  如下:Phone does not implement Usb (missing Stop method)
    func (p Phone) Stop() {
        fmt.Println("手机断开了USB,停止工作")
    }
    
    type IPad struct {
        Name  string
        Price int
    }
    
    func (p IPad) Start() {
        fmt.Println("ipad已经连接USB,开始工作")
    }
    
    func (p IPad) Stop() {
        fmt.Println("ipad断开了USB,停止工作")
    }
    
    //定义一个电脑结构体,这个结构体可以实现usb的接口
    type Computer struct {
    }
    
    //定义working方法,接收Usb接口类型变量
    //实现Usb接口声明的所有方法
    //这是一个多态的函数,调用同一个Working函数,不同的执行结果
    func (mbp Computer) Working(usb Usb) {
        //不同的usb实参,实现不同的功能
        //只要实现了usb接口的数据类型,那么这个类型的变量,就可以给usb接口变量赋值
        usb.Start()
        usb.Stop()
    }
    
    func main() {
        //分别创建结构体对象
        c := Computer{}
        p := Phone{"苹果手机", 6999}
        i := IPad{"华为平板", 7999} 
    
        //
        //手机连接笔记本,插上手机
        c.Working(p)
        fmt.Printf("名字:%v 价格:%d
    ", p.Name, p.Price)
    
        fmt.Println("------------------")
        //平板连接笔记本,插上平板
        c.Working(i)
        fmt.Printf("名字:%v 价格:%d
    ", i.Name, i.Price)
    }
    

    接口实例2

    package main
    
    import "fmt"
    
    //员工接口
    type Employer interface {
        CalcSalary() float32
    }
    
    //开发者
    type Programer struct {
        name  string
        base  float32
        extra float32
    }
    
    //创建开发者实例
    func NewProgramer(name string, base float32, extra float32) Programer {
        return Programer{
            name,
            base,
            extra,
        }
    }
    
    //计算开发者工资,实现了CalcSalary方法
    func (p Programer) CalcSalary() float32 {
        return p.base
    }
    
    //销售群体
    type Sale struct {
        name  string
        base  float32
        extra float32
    }
    
    //创建销售实例
    func NewSale(name string, base float32, extra float32) Sale {
        return Sale{
            name,
            base,
            extra,
        }
    }
    
    //实现了CalcSalary方法
    func (p Sale) CalcSalary() float32 {
        return p.base + p.extra*p.base*0.5
    }
    
    //计算所有人的工资接收参数,接口切片
    func calcAll(e []Employer) float32 {
        /*
            fmt.Println(e)
            [{码云 50000 0} {刘抢东 40000 0} {麻花藤 30000 0} {格格 3000 2.5} {小雪 1800 2.5} {小雨 2000 2.5}]
        */
        var cost float32
        //忽略索引,v是每一个结构体
        for _, v := range e {
            cost = cost + v.CalcSalary()
        }
        return cost
    }
    func main() {
        p1 := NewProgramer("码云", 50000.0, 0)
        p2 := NewProgramer("刘抢东", 40000, 0)
        p3 := NewProgramer("麻花藤", 30000, 0)
    
        s1 := NewSale("格格", 3000, 2.5)
        s2 := NewSale("小雪", 1800, 2.5)
        s3 := NewSale("小雨", 2000, 2.5)
    
        var employList []Employer
        employList = append(employList, p1)
        employList = append(employList, p2)
        employList = append(employList, p3)
        employList = append(employList, s1)
        employList = append(employList, s2)
        employList = append(employList, s3)
    
        cost := calcAll(employList)
        fmt.Printf("这个月人力成本:%f
    ", cost)
    }
    

    1.3. Go接口细节

    1.接口本身不能创建实例,但是可以指向一个实现了该接口的变量实例,如结构体
    2.接口中所有方法都没有方法体,是没有实现的方法
    3.Go中不仅是struct可以实现接口,自定义类型也可以实现接口,如type myInt int 自定义类型
    4.一个自定义类型,只有实现了某个接口,才可以将自定义类型的实例变量,赋给接口类型,否则报错missing xx method
    5.一个自定义类型,可以实现多个接口(实现多个接口的所有方法)
    6.接口类型不得写入任何变量 如
    type Usb interface{
        method1()
        method2()
        Name string  //错误,编译器不通过
    }
    7.接口A可以继承多个别的接口B、接口C,想要实现A,也必须实现B、C所有方法,称作接口组合
    8.interface类型,默认是指针(引用类型),如果没初始直接使用,输出nil,可以赋给实现了接口的变量
    9.空接口interface{},没有任何类型,也就是实现了任何类型,可以吧任何一个变量赋给空接口
    10.匿名组合的接口,不可以有同名方法,否则报错duplicate method
    

    1.3.1. 空接口

    package main
    
    import "fmt"
    
    type A interface {
    }
    
    type Cat struct {
        name string
        age  int
    }
    
    type Person struct {
        name string
        sex  string
    }
    
    //参数类型是接口类型,可以接收任意类型数据
    func test1(a A) {
        fmt.Println(a)
    
    }
    
    //
    func test2(a interface{}) {
        fmt.Println(a)
    
    }
    
    //数组元素是接口,可以存放任意不同的数据类型,输出不同类型
    func test3(slice2 []interface{}) {
    
        for i := 0; i < len(slice2); i++ {
            //数组中元素类型不同,通过接口的类型断言判断
            switch ins := slice2[i].(type) {
            case Cat:
                fmt.Println("	传入cat对象:", ins.name, ins.age)
            case Person:
                fmt.Println("	传入person对象:", ins.name, ins.sex)
            case int:
                fmt.Println("	传入了int类型:", ins)
            case string:
                fmt.Print("	传入了string类型:", ins)
            }
        }
    }
    
    func main() {
        a1:=Cat{"花花",1}
        p1:=Person{"锐萌萌","女性"}
        i1:=123
        s1:="峡谷之巅,最强王者"
    
        test1(a1)
        test2(p1)
        //test3接收切片类型
        //初始化一个切片s1
        slice1:=[]interface{}{}
        fmt.Println(slice1,len(slice1),cap(slice1))
        fmt.Println("你好")
    
        slice1=append(slice1,a1,p1,i1,s1)
        fmt.Println(slice1)
    
        //传入切片
        test3(slice1)
    }
  • 相关阅读:
    英国下院通过法案允许合成人兽胚胎
    老外关于思考时间的问与答
    性能测试中用LambdaProbe监控Tomcat
    BT下载原理
    汽车维修行业呼吁大学生加入修车行列
    一个女研究生(高级测试工程师)的职业选择
    微软称20日验证Windows与Office 盗版将黑屏 网友评论
    Xbox摇身变NAS:BT的使用问题与性能测试
    李开复建言大学生:求职中不要把钱看得太重
    IBM雇员将罢工15分钟 为抗议公司裁员
  • 原文地址:https://www.cnblogs.com/open-yang/p/11256892.html
Copyright © 2011-2022 走看看