zoukankan      html  css  js  c++  java
  • GO基础之接口

    一、概念
    1、 面向对象语言中,接口用于定义对象的行为。接口只指定对象应该做什么,实现这种行为的方法(实现细节)是由对象来决定。
    2、 在Go语言中,接口是一组方法签名。

    • •接口只指定了类型应该具有的方法,类型决定了如何实现这些方法。
    • •当某个类型为接口中的所有方法提供了具体的实现细节时,这个类型就被称为实现了该接口。
    • •接口定义了一组方法,如果某个对象实现了该接口的所有方法,则此对象就实现了该接口。

    3、 Go语言的类型都是隐式实现接口的。任何定义了接口中所有方法的类型都被称为隐式地实现了该接口。

    二、接口的使用

    go没有 implements, extends 关键字,其实这种编程语言叫做duck typing编程语言。

    package main
    
    import "fmt"
    import "base"
    
    //定义接口
    type Phone interface {
        call()
    }
    
    type AndroidPhone struct {
    }
    
    type IPhone struct {
    }
    
    func (a AndroidPhone) call() {
        fmt.Println("我是安卓手机,可以打电话了")
    }
    
    func (i IPhone) call() {
        fmt.Println("我是苹果手机,可以打电话了")
    }
    
    func main() {
        //    定义接口类型的变量
        var phone Phone
        //phone = new(AndroidPhone)
        phone = AndroidPhone{}
        fmt.Printf("%T , %v , %p 
    " , phone , phone , &phone)
        phone.call()
    
        //phone = new(IPhone)
        phone = IPhone{}
        fmt.Printf("%T , %v , %p 
    " , phone , phone , &phone)
        phone.call()
    }
    View Code


     动态类型与静态类型语言

    • •动态类型的好处很多,Python代码写起来很快。但是缺陷也是显而易见的:错误往往要在运行时才能被发现。
    • •相反,静态类型语言往往在编译时就是发现这类错误:如果某个变量的类型没有显式声明实现了某个接口,那么,这个变量就不能用在要求一个实现了这个接口的地方。

     Go类型系统采取了折中的办法:
    •之所以说这是一种折中的办法,原因如下:

    • 〇第一,结构体类型T不需要显式地声明它实现了接口 I。只要类型T实现了接口1规定的所有方法,它就自动地实现了接口 I。这样就像动态语言一样省了很多代码,少了许多限制。
    • 〇第二,将结构体类型的变量显式或者隐式地转换为接口 I类型的变量i。这样就可以和其它静态类型语言一样,在编译时检查参数的合法性。

    三、多态

    •事物的多种形态

    • • Go中的多态性是在接口的帮助下实现的。定义接口类型,仓U建实现该接口的结构体对象。
    • •定义接口类型的对象,可以保存实现该接口的任何类型的值。Go语言接口变量的这个特性实现了 Go语言中的多态性。
    • •接口类型的对象,不能访问其实现类中的属性字段。
    package main
    
    import "fmt"
    import "base"
    
    
    type Income interface {
        calculate() float64 //计算收入总额
        source() string     //用来说明收入来源
    }
    
    //固定账单项目
    type FixedBilling struct {
        projectName  string  //工程项目
        biddedAmount float64 //项目招标总额
    }
    
    //定时生产项目(定时和材料项目)
    type TimeAndMaterial struct {
        projectName string
        workHours   float64 //工作时长
        hourlyRate  float64 //每小时工资率
    }
    
    //固定收入项目
    func (f FixedBilling) calculate() float64 {
        return f.biddedAmount
    }
    
    func (f FixedBilling) source() string {
        return f.projectName
    }
    
    //定时收入项目
    func (t TimeAndMaterial) calculate() float64 {
        return t.workHours * t.hourlyRate
    }
    
    func (t TimeAndMaterial) source() string {
        return t.projectName
    }
    
    //通过广告点击获得收入
    type Advertisement struct {
        adName         string
        clickCount     int
        incomePerclick float64
    }
    
    func (a Advertisement) calculate() float64 {
        return float64(a.clickCount) * a.incomePerclick
    }
    
    func (a Advertisement) source() string {
        return a.adName
    }
    
    func main() {
        p1 := FixedBilling{"项目1", 5000}
        p2 := FixedBilling{"项目2", 10000}
        p3 := TimeAndMaterial{"项目3", 100, 40}
        p4 := TimeAndMaterial{"项目4", 250, 20}
        p5 := Advertisement{"广告1", 10000, 0.1}
        p6 := Advertisement{"广告2", 20000, 0.05}
    
        ic := []Income{p1, p2, p3, p4, p5, p6}
        fmt.Println("total=",calculateNetIncome(ic))
    }
    
    //计算净收入
    func calculateNetIncome(ic []Income) float64 {
        netincome := 0.0
        for _, income := range ic {
            fmt.Printf("收入来源:%s ,收入金额:%.2f 
    ", income.source(), income.calculate())
            netincome += income.calculate()
        }
        return netincome
    }
    View Code

    四、空接口

    •空接口 :该接口中没有任何的方法。任意类型都可以实现该接口。
    •空interface这样定义:interface{},也就是包含0个method的interface。
    •用空接口表示任意数据类型。类似于java中的object。
    •空接口常用于以下情形:
    〇 1、println的参数就是空接口
    〇 2、定义一个map: key是string,value是任意数据类型
    〇 3、定义一个切片,其中存储任意类型的数据

    package main
    
    import (
        "fmt"
    )
    
    type A interface {
    }
    
    type Cat struct {
        name string
        age  int
    }
    
    type Person struct {
        name string
        sex  string
    }
    
    func main() {
        var a1 A = Cat{"Mimi", 1}
        var a2 A = Person{"Steven", ""}
        var a3 A = "Learn golang with me!"
        var a4 A = 100
        var a5 A = 3.14
    
        showInfo(a1)
        showInfo(a2)
        showInfo(a3)
        showInfo(a4)
        showInfo(a5)
        fmt.Println("------------------")
    
        //1、fmt.println参数就是空接口
        fmt.Println("println的参数就是空接口,可以是任何数据类型", 100, 3.14, Cat{"旺旺", 2})
    
        //2、定义map。value是任何数据类型
        map1 := make(map[string]interface{})
        map1["name"] = "Daniel"
        map1["age"] = 13
        map1["height"] = 1.71
        fmt.Println(map1)
        fmt.Println("------------------")
    
        //    3、定义一个切片,其中存储任意数据类型
        slice1 := make([]interface{}, 0, 10)
        slice1 = append(slice1, a1, a2, a3, a4, a5)
        fmt.Println(slice1)
    
        transInterface(slice1)
    
        //var cat1 A = Cat{"MiaoMiao" , 3}
        //fmt.Println(cat1.name , cat1.age)
    
    }
    
    //接口对象转型
    //接口对象.(type),配合switch...case语句
    func transInterface(s []interface{}) {
        for i := range s {
            fmt.Println("", i+1 , "个数据:")
            switch t := s[i].(type) {
            case Cat:
                fmt.Printf("	 Cat对象,name属性:%s,age属性:%d 
    " , t.name , t.age)
            case Person:
                fmt.Printf("	 Person对象,name属性:%s,sex属性:%s 
    " , t.name , t.sex)
            case string:
                fmt.Println("	 string类型" , t)
            case int:
                fmt.Println("	 int类型" , t)
            case float64:
                fmt.Println("	 float64类型" , t)
            }
        }
    }
    
    func showInfo(a A) {
        fmt.Printf("%T , %v 
    ", a, a)
    }
    View Code

    五、接口对象转型
    1、 方式一:
    • instance, ok :=接口对象.(实际类型)
    •如果该接口对象是对应的实际类型,那么instance就是转型之后对象,ok的值为true
    •配合if... else if...语句使用
    2、 方式二:
    •接口对象.(type)
    •配合switch...case语句使用

    package main
    
    import "fmt"
    import (
        "base"
        "math"
    )
    
    //1、定义接口
    type Shape interface {
        perimeter() float64
        area() float64
    }
    
    //2.矩形
    type Rectangle struct {
        a, b float64
    }
    
    //3.三角形
    type Triangle struct {
        a, b, c float64
    }
    
    //4.圆形
    type Circle struct {
        radius float64
    }
    
    //定义实现接口的方法
    func (r Rectangle) perimeter() float64 {
        return (r.a + r.b) * 2
    }
    
    func (r Rectangle) area() float64 {
        return r.a * r.b
    }
    
    func (t Triangle) perimeter() float64 {
        return t.a + t.b + t.c
    }
    
    func (t Triangle) area() float64 {
        //海伦公式
        p := t.perimeter() / 2 //半周长
        return math.Sqrt(p * (p - t.a) * (p - t.b) * (p - t.c))
    }
    
    func (c Circle) perimeter() float64 {
        return 2 * math.Pi * c.radius
    }
    
    func (c Circle) area() float64 {
        return math.Pow(c.radius, 2) * math.Pi
    }
    
    //接口对象转型方式1
    //instance,ok := 接口对象.(实际类型)
    func getType(s Shape) {
        if instance, ok := s.(Rectangle); ok {
            fmt.Printf("矩形:长度%.2f , 宽度%.2f , ", instance.a, instance.b)
        } else if instance, ok := s.(Triangle); ok {
            fmt.Printf("三角形:三边分别:%.2f , %.2f , %.2f , ", instance.a, instance.b, instance.c)
        } else if instance, ok := s.(Circle); ok {
            fmt.Printf("圆形:半径%.2f , ", instance.radius)
        }
    }
    
    //接口对象转型——方式2
    //接口对象.(type),  配合switch和case语句使用
    func getType2(s Shape) {
        switch instance := s.(type) {
        case Rectangle:
            fmt.Printf("矩形:长度为%.2f , 宽为%.2f ,	", instance.a, instance.b)
        case Triangle:
            fmt.Printf("三角形:三边分别为%.2f ,%.2f , %.2f ,	", instance.a, instance.b, instance.c)
        case Circle:
            fmt.Printf("圆形:半径为%.2f ,	", instance.radius)
        }
    }
    
    func getResult(s Shape) {
        getType2(s)
        fmt.Printf("周长:%.2f ,面积:%.2f 
    ", s.perimeter(), s.area())
    }
    
    func main() {
        var s Shape
        s = Rectangle{3, 4}
        getResult(s)
        showInfo(s)
    
        s = Triangle{3, 4, 5}
        getResult(s)
        showInfo(s)
    
        s = Circle{1}
        getResult(s)
        showInfo(s)
    
        x := Triangle{3, 4, 5}
        fmt.Println(x)
    
    }
    
    func (t Triangle) String() string {
        return fmt.Sprintf("Triangle对象,属性分别为:%.2f, %.2f, %.2f", t.a, t.b, t.c)
    }
    
    func showInfo(s Shape) {
        fmt.Printf("%T ,%v 
    ", s, s)
        fmt.Println("-------------------")
    }
    View Code
  • 相关阅读:
    swift5.x 错误处理
    iOS--iPhoneX设备判断
    swift5.x 多线程的应用场景
    Swift5.x 多线程编程
    Swift5.x 范型
    swift5.x 类初始化、反初始化, 指定初始化器,便利初始化器
    swift5.x 扩展(extension)
    swift5.x 多态,类型检查,类型转换
    Effective java笔记(十),序列化
    Effective java笔记(九),并发
  • 原文地址:https://www.cnblogs.com/jalja/p/11815652.html
Copyright © 2011-2022 走看看