当前位置: 移动技术网 > IT编程>脚本编程>Go语言 > GO基础之接口

GO基础之接口

2019年11月08日  | 移动技术网IT编程  | 我要评论
面向对象语言中,接口用于定义对象的行为。接口只指定对象应该做什么,实现这种行为的方法(实现细节)是由对象来决定。 ...

一、概念
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 \n" , phone , phone , &phone)
    phone.call()

    //phone = new(iphone)
    phone = iphone{}
    fmt.printf("%t , %v , %p \n" , phone , phone , &phone)
    phone.call()
}


 动态类型与静态类型语言

  • •动态类型的好处很多,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 \n", income.source(), income.calculate())
        netincome += income.calculate()
    }
    return netincome
}

 

四、空接口

•空接口 :该接口中没有任何的方法。任意类型都可以实现该接口。
•空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("\t cat对象,name属性:%s,age属性:%d \n" , t.name , t.age)
        case person:
            fmt.printf("\t person对象,name属性:%s,sex属性:%s \n" , t.name , t.sex)
        case string:
            fmt.println("\t string类型" , t)
        case int:
            fmt.println("\t int类型" , t)
        case float64:
            fmt.println("\t float64类型" , t)
        }
    }
}

func showinfo(a a) {
    fmt.printf("%t , %v \n", a, a)
}

五、接口对象转型
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 ,\t", instance.a, instance.b)
    case triangle:
        fmt.printf("三角形:三边分别为%.2f ,%.2f , %.2f ,\t", instance.a, instance.b, instance.c)
    case circle:
        fmt.printf("圆形:半径为%.2f ,\t", instance.radius)
    }
}

func getresult(s shape) {
    gettype2(s)
    fmt.printf("周长:%.2f ,面积:%.2f \n", 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 \n", s, s)
    fmt.println("-------------------")
}

 

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网