这篇学习接口,接口是golang语言重要的特性之一

 

一、接口介绍

接口是对其它类型行为的抽象和概括,也就是方法的集合,但不用实现这些方法。

如果一个自定义类型包含了接口里面所有的方法,那么可以说这个自定义类型实现了这个接口,而且是隐式实现的

接口也是一种数据类型(指针),多态特性是通过接口来体现的

接口的作用是高内聚,低耦合
 
type 接口名 interface {
    方法名1(参数列表) 返回值列表
    方法名2(参数列表) 返回值列表
    方法名3(参数列表) 返回值列表
    ...
}
package main

import "fmt"

// Hello接口
type Helloer interface {
    Sayhello()
}

// Usa结构体
type Usa struct {
    Name string
} 

// Chinese结构体
type Chinese struct {
    Name string
}

func (h *Usa)  Sayhello() {
    fmt.Println("hello")
}

func (c *Chinese) Sayhello() {
    fmt.Println("你好")
}

func main() {
    // 将Usa结构体实例赋值给hello接口类型bob
    var bob Helloer = &Usa{"Bob"}
    // 将Chinese结构体实例赋值给hello接口类型alice
    var alice Helloer = &Chinese{"Alice"} 
    // 调用相同的Sayhelo方法不同的结果
    bob.Sayhello()  // hello
    alice.Sayhello() // 你好
    // 不能访问字段属性,接口只关注方法
    fmt.Println(bob.Name)
    fmt.Println(alice.Name)
}

三、接口使用注意与细节

 一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)覆给接口类型

package main
import "fmt"

type Test interface {
    test01()
    test02()
}

// A结构体没有实现Test结构
type A struct {
}

func (a A) test01() {
    fmt.Println("test01")
}

func main() {
    var a = A{}  // 接口体实例
    var t Test = a  // 将结构体a赋值给接口类型t (报错, 因为a实例并没有实现Test接口,缺少test02方法,所以不能赋值)
}
package main

import (
    "fmt"
)

// 定义一个Integer接口
type Integer interface {
    add(x integer) integer // 声明add方法
}

// 自定义类型(int别名)
type integer int 

// 实现了Integer接口, 因为有add方法
func (i integer) add(x integer) integer {
    return i + x
}

func main()  {
    var i, s integer = 5
    fmt.Println(i.add(s))    // 10
}
    package main

    import (
        "fmt"
    )

    // File结构体同时实现了Writer和Reader接口
    type Writer interface {
        writer()
    }

    type Reader interface {
        reader()
    }

    type File struct {
        Name string
    }

    func (f *File) reader() {
        fmt.Println("读取文件: ", f.Name)
    }

    func (f *File) writer() {
        fmt.Println("写入文件: ", f.Name)
    }

    func main()  {
        var w Writer = &File{"/etc/passwd"}  // 写入文件:  /etc/passwd
        var r Reader = &File{"/etc/passwd"}  // 读取文件:  /etc/passwd
        w.writer()
        r.reader()
    }
    package main

    import (
        "fmt"
    )

    // MI和Huawei结构体实现了同一个Phoner接口

    type Phoner interface {
        Call()
        Start()
    }

    // MI结构体,实现了Phoner接口
    type MI struct {
        Name string
    }

    func (m *MI) Call() {
        fmt.Println("mi: Call")
    }

    func (m *MI) Start() {
        fmt.Println("mi: Start")
    }

    // Huawei结构体,实现了Phoner接口
    type Huawei struct {
        Name string
    }

    func (h *Huawei) Call() {
        fmt.Println("huawei: Call")
    }

    func (h *Huawei) Start() {
        fmt.Println("huawei: Start")
    }

    func main()  {
        var m Phoner = &MI{"mi"}
        var h Phoner = &Huawei{"huawei"}
        m.Start()
        m.Call()
        h.Start()
        h.Call()
    }

如果一个接口没有声明方法就是空接口,空接口没有初始化使用,那么它的值是nil。由于空接口没有方法,所以任何类型都实现了空接口

// 空接口,它的值是nil
type Interface interface {
}

type Student struct {
    Name string
}

func main() {
    // 空接口的值默认是nil
    var i Interface
    if i == nil {
        fmt.Println(i) // <nil>
    }

    // 任何类型都可以实现空接口
    var x Interface = &Student{"Bob"}
    var y Interface = &Student{"Alice"}
    fmt.Println(x, y)
}
package main

import "fmt"

// A接口
type A interface {
    test01()
}

// B接口
type B interface {
    test02()
}
// 嵌入A和B接口,实现了接口继承
type C interface {
    A
    B
    test03()
}

// Test结构体,实现了C接口
type Test struct {
}

func (t *Test) test01() {
    fmt.Println("test01")
}

func (t *Test) test02() {
    fmt.Println("test02")
}

func (t *Test) test03() {
    fmt.Println("test03")
}

func main() {
    // 变量的t的类型是C接口
    var t C = &Test{}
    // fmt.Println(t)
    t.test01()  // test01
    t.test02()  // test02
    t.test03()  // test03
}
package main

import (
    "fmt"
)

// Bird接口
type Bird interface {
    Fly()
}

// Fish接口
type Fish interface {
    Swimming()
}

type Monkey struct {
    Name string
}

// 继承Monkey结构体
type Little struct {
    Monkey
}

// Monkey的climbing方法
func (m *Monkey) climbing() {
    fmt.Println(m.Name, "生来会爬树")
}

// Little结构体方法,实现Bird接口(扩展)
func (l *Little) Fly() {
    fmt.Println(l.Name, "会飞翔")
}

// Little结构体方法, 实现Fish接口(扩展)
func (l *Little) Swimming() {
    fmt.Println(l.Name, "会游泳")
}

func main() {
    dasheng := &Little{Monkey{"大圣"}}
    // fmt.Println(dasheng.Name)
    dasheng.climbing() // 大圣 生来会爬树
    dasheng.Fly()      // 大圣 会飞翔
    dasheng.Swimming() // 大圣 会游泳
}
package main

import "fmt"

type Animal interface{
    Say()
}
// 实现Animal接口
type Cat struct {
    Name string
}
// 实现Animal接口 type Dog struct { Name string } func (c *Cat) Say() { fmt.Println("喵喵") } func (d *Dog) Say() { fmt.Println("汪汪") } func say(s Animal) { s.Say() } func main() { miao := &Cat{"小猫"} dog := &Dog{"小狗"} say(miao) // 喵喵 miao是Cat类型的实例,Cat结构体实现了Animal接口,所以可以传给say函数的s参数(Animal类型) say(dog) // 汪汪 dog是Dog类型的实例,Dog结构体实现了Animal接口,所以可以传给say函数肚饿s参数(Animal类型) }
package main

import "fmt"

func main() {
    // 空接口
    var i interface{}
    i = 10   // 谁都可以实现空接口i
    // fmt.Println(i)
    
    // 断言, i接口变量是int类型吗?
    data, ok := i.(int)
    if ok {
        fmt.Printf("data的类型为int, 值是: %v\n", data)
    }
    i = 3.14
    // fmt.Println(i)

    // 断言, i接口变量是float64类型吗?
    d, isok := i.(float64)
    if isok {
        fmt.Printf("data的类型为float64, 值是: %v\n", d)  
    } else {
        fmt.Println("data类型不是float64")
    }
}
func main() {
    // 空接口变量a
    var a interface{}
    // Point结构体体实例point,实现了空接口a
    var point Point = Point{1,2}
    // 将point赋值给a
    a = point
    // 声明一个变量b,类型为Point
    var b Point
    // 类型断言,判断a是否为指向Point类型的变量,如果是转换成Point类型并赋给b变量,否则报错
    b, ok = a.(Point)
    if ok {
        fmt.Println(b)
    } else {
        fmt.Println("error handle")
    }
}
package main

import "fmt"

type Usb interface {
    start()
    stop()
}

type Phone struct{
    Name string
}

type Camera struct {
    Name string
}

func (p *Phone) start() {
    fmt.Println(p.Name, "开始工作")
}

func (p *Phone) stop() {
    fmt.Println(p.Name, "停止工作")
}

func (p *Phone) call() {
    fmt.Println(p.Name, "打电话")
}

func (c *Camera) start() {
    fmt.Println(c.Name, "开始工作")
}

func (c *Camera) stop() {
    fmt.Println(c.Name, "停止工作")
}

func Working(usb Usb) {
    usb.start()
    if ob, ok := usb.(*Phone); ok {
        ob.call()
    }
    usb.stop()
}

func main() {
    array := [2]Usb{&Phone{"xiaomi"}, &Camera{"canon"}}
    for _, i := range array {
        // fmt.Println(i)
        Working(i)
    }
}
// 自定义类型
type Student struct {
    Name string
    Age int
}

func CheckType(items ...interface{}) {
    for _, x := range items {
        // type是固定的写法
        switch x.(type) {
        case int, int64:
            fmt.Printf("参数是int类型, 值是%v\n", x)
        case float64:
            fmt.Printf("参数是float64类型, 值是%v\n", x)
        case string:
            fmt.Printf("参数是string类型, 值是%v\n", x)
        case bool:
            fmt.Printf("参数是bool类型, 值是%v\n", x)
        case Student:
            fmt.Printf("参数是Student类型, 值是%v\n", x)
        case *Student:
            fmt.Printf("参数*Student类型, 值是%v\n", x)
        case nil:
            fmt.Printf("参数是nil类型, 值是%v\n", x)
        default:
            fmt.Printf("参数是不知道的类型, 值是%v\n", x)
        }
    }
}

func main() {
    // 可以传不同类型的参数到CheckType函数,因为CheckType函数的参数是一个空接口
    CheckType(1, "abc", 3.14, true, Student{"Bob", 20}, &Student{"Alice", 30})
}

// 输出
参数是int类型, 值是1
参数是string类型, 值是abc
参数是float64类型, 值是3.14
参数是bool类型, 值是true
参数是Student类型, 值是{Bob 20}
参数*Student类型, 值是&{Alice 30