【Go语言】接口编程

一、接口的基本概念

接口的定义

  • 接口是一组行为规范的集合
  • 接口名通常以 er 结尾
  • 接口里只定义方法,不定义变量
  • 参数列表和返回值列表里的变量名可以省略
type Transporter interface {
    distance(src string, dest string) float64
    expenses(int) int
    takeTime(float64,float64) time.Time
}

 

接口的实现

  • 定义结构体时无需显式声明要实现的对应接口,只要结构体拥有接口里声明的所有方法,就称该结构体“实现了接口”
  • 一个结构体可以实现多个接口

Car 实现接口 Transporter

type Transporter interface {
    distance(src string, dest string) float64
    expenses(src string, dest string) int
    takeTime(src string, dest string) float64
}

var city = map[string]int{
    "bj": 31893,
    "sz": 34348,
    "hk": 34987,
}

type Car struct {
    model string
    speed float64
    cost  float64
}

func (Car) distance(src, dest string) float64 {
    s := float64(city[src] - city[dest])
    s = math.Abs(s)
    return s
}

func (car Car) expenses(src, dest string) int {
    c := car.distance(src, dest) * 9.2 * car.cost
    return int(c)
}
func (car Car) takeTime(src, dest string) float64 {
    t := car.distance(src, dest) / car.speed
    return t
}

 

接口的本质

接口值由两部分组成:

指向该接口的具体类型的指针(结构体类型定义的指针)

指向该具体类型真实数据的指针(实例化的结构体变量的值)

 

接口的使用

范例:

type Transporter interface {
    distance(src string, dest string) float64
    expenses(src string, dest string) int
    takeTime(src string, dest string) float64
}

var city = map[string]int{
    "bj": 31893,
    "sz": 34348,
    "hk": 34987,
}

type Car struct {
    model string
    speed float64
    cost  float64
}

func (Car) distance(src, dest string) float64 {
    s := float64(city[src] - city[dest])
    s = math.Abs(s)
    return s
}

func (car Car) expenses(src, dest string) int {
    c := car.distance(src, dest) * 9.2 * car.cost
    return int(c)
}
func (car Car) takeTime(src, dest string) float64 {
    t := car.distance(src, dest) / car.speed
    return t
}

func Transportinfo(src, dest string, t Transporter) {
    s := t.distance(src, dest)
    times := t.takeTime(src, dest)
    c := t.expenses(src, dest)
    fmt.Printf("distance is %2.f KM\n", s)
    fmt.Printf("takeTime is %2.f h\n", times)
    fmt.Printf("expenses is ¥%d\n", c)
}

func main() {
    car := Car{"BMW", 120, 0.08}
    Transportinfo("bj", "sz", car)
}

输出结果:

 

接口的赋值

实现指针的结构体方法中如果全部使用 值接收 方法,则在接口赋值时可以使用 值赋值 或 指针赋值

如果实现指针的结构体方法中存在 指针接收 方法,则在接口赋值时只能使用 指针赋值

实现了接口的结构体可以直接赋值给接口

type Transporter interface {
    distance(src string, dest string) float64
    expenses(src string, dest string) int
    takeTime(src string, dest string) float64
}

// 方法接收的是值
func (car Car) expenses(src, dest string) int {
    c := car.distance(src, dest) * 9.2 * car.cost
    return int(c)
}

// 方法接收指针,则实现接口的是指针类型
func (plane *Plane) expenses(src, dest string) int {
    c := (*plane).distance(src, dest)*3*float64((*plane).level) + float64((*plane).base)
    return int(c)
}

func main() {
    car := Car{"BMW", 120, 0.08}
    plane := Plane{1, 800, 10, 50}
    var t Transporter
    t = car // 方法都是接收值,接口赋值可以使用值赋值
    println(t.expenses("bj", "sz"))
    t = &car // 方法都是接收值,接口赋值也可以实现指针赋值
    println(t.expenses("bj", "sz"))
    t = &plane // 存在方法接收指针,接口赋值必须使用指针赋值
    println(t.expenses("bj", "sz"))
}

 

二、接口嵌入

type Transporter interface {
    distance(src string, dest string) float64
    expenses(src string, dest string) int
    takeTime(src string, dest string) float64
}

type Plan interface {
    Transporter
    IsAllow(int) bool
}

 

三、空接口

  • 空接口类型用 interface{} 表示
  • 空接口没有定义任何方法,因此任意类型都实现了空接口
  • func squrae(x interface{}) {}  该函数可以接收任意数据类型作为入参
  • slice 元素、map 的 key,value 都可以是空接口类型

 

四、类型断言

在未知变量对应数据类型时,通过假设类型进行类型判断

当需要进行判断的类型较多时,需要使用很多次的 if-else,更好方案是使用 switch i.(type)  可参考:https://www.cnblogs.com/Janzen-q/p/17591775.html

func type_if (i interface{}){

    if v,ok :=i.(int); ok {  // 此时 i 为未知类型的变量,进行类型断言int,如果断言成功,ok 为 true, v 是具体类型的值
        fmt.Printf("i type is int, i = %d",v)
    } else {
        fmt.Printf("i type is not int")
    }
}

 

 

五、面向接口编程

  • 在框架层面全是接口
  • 具体的实现由不同的开发者去完成,每种实现单独放到一个go文件中,代码之间互不干扰
  • 通过配置选择采用的实现方式,便于进行效果对比

案例项目链接:https://files.cnblogs.com/files/blogs/693302/rec.zip?t=1691431448&download=true

posted @ 2023-08-08 02:05  Janzen_Q  阅读(20)  评论(0编辑  收藏  举报