Go语言接口interface

1.接口的介绍与定义

1.定义

  • 接口定义了一个对象的行为规范
    • A:只定义规范,不实现
    • B:具体的对象需要实现规范的细节

2.表现形式

  • 1.type 接口名字 interface
  • 2.接口里面是一组方法签名的集合
type Animal interface {
    Talk()
    Eat()
    Run()
}

3.实现

  • 1.一个对象只要包含接口中的方法,那么就实现了这个接口
  • 2.接口类型的变量可以保存具体类型的实例

4.实例

  • 1.一个公司需要计算所有职员的薪水
  • 2.每个职员的薪水计算方式不同
package main

import "fmt"


// 定义一个员工的接口,接口中定义CalcSalary方法
type Employer interface {
    CalcSalary() float64
}

// 函数:实现所有员工薪水的统计
func calcAll(e []Employer) float64 {
    var cost float64
    for _, v := range e {
	cost += v.CalcSalary()
    }
    return cost
}

type Programmer struct {
    name string
    base float64
    extra float64
}

// 为Programmer对象添加接口Employer中定义的CalcSalary方法
// Programmer对象实现了Employer接口
func (p *Programmer) CalcSalary() float64 {
    return p.base
}

// 构造一个程序员
func NewProgrammer(name string, base float64, extra float64) *Programmer {
    return &Programmer{
	name:  name,
        base:  base,
	extra: extra,
    }
}

type Seller struct {
    name string
    base float64
    extra float64
}

func (s *Seller) CalcSalary() float64 {
    return s.base + s.Sales * s.ratio
}

func NewSeller(name string, base, Sales, ratio float64) *Seller {
    return &Seller{
	name: name,
	base:  base,
	Sales:  Sales,
	ratio: ratio,
    }
}

func main()  {
    p1 := NewProgrammer("小李", 12000, 0)
    p2 := NewProgrammer("小王", 8000, 0)
    p3 := NewProgrammer("小胡", 8500, 0)

    s1 := NewSeller("张倩", 4500, 12000, 0.06)
    s2 := NewSeller("王艳", 4500, 8000, 0.04)
    s3 := NewSeller("李梅", 4500, 5600, 0.03)

    var employerList []Employer
    employerList = append(employerList, p1)
    employerList = append(employerList, p2)
    employerList = append(employerList, p3)
    employerList = append(employerList, s1)
    employerList = append(employerList, s2)
    employerList = append(employerList, s3)

    cost := calcAll(employerList)
    fmt.Println(cost)
}

5.接口类型的变量

  • 1.Var a Animal
  • 2.那么a能够存储所有实现Animal接口的实例
package main

import "fmt"

type Animal interface {
    Eat()
}

type Dog struct {
    Name string
}

// 值类型实现Dog对象方法  ------>  引用类型实现  fun(d *Dog)
func (d Dog) Eat() {
    fmt.Printf("小狗%s正在啃骨头\n", d.Name)
}

type Cat struct {
    Name string
}

func (c Cat) Eat() {
    fmt.Printf("小猫%s正在吃鱼\n", c.Name)
}

func main()  {
    var a Animal
    var dog Dog
    var cat Cat
    a = dog
    a.Eat()

    a = cat
    a.Eat()
}

2.空接口和类型断言

1.空接口

  • 1.空接口没有定义任何方法
  • 2.所以任何类型都实现了空接口
var a interface{}

var b []byte
a = b
fmt.Println(a)  // []

var c map[string]int
a = c
fmt.Println(a)  // map[]

var d rune
a = d
fmt.Println(a)  // 0
  • 3.空接口可以作为函数的形参,接收任意类型的值
package main

import "fmt"


func describe(a interface{})  {
    fmt.Printf("%T %v\n", a, a)
}

type Stu struct {
    Name string
    Age int
}

func main()  {
    inta := 65
    describe(inta)  // int 65

    var stu = Stu{
        Name: "小亮",
        Age:  23,
    }
    describe(stu)  // main.Stu {小亮 23}
}

2.类型断言

  • 1.如何获取接口类型里面存储的具体的值呢:a.(T)
func describe(a interface{})  {
    v, ok := a.(int)
    if ok {
	fmt.Println(v)
    } else {
	fmt.Printf("%T %v\n", a, a)
    }
}
  • 2.使用typy switch
// 两次调用a.(type)
func describe(a interface{})  {
    switch a.(type) {
    case string:
	fmt.Printf("a is string, value:%v\n", a.(string))
    case int:
	fmt.Printf("a is int, value:%v\n", a.(int))
    case map[string]int:
	fmt.Printf("a is map, value:%v\n", a.(map[string]int))
    default:
	fmt.Println("不支持的类型")
    }
}
// 优化写法(推荐)
func describe(a interface{})  {
    switch v := a.(type) {
    case string:
	fmt.Printf("a is string, value:%v\n", v)
    case int:
	fmt.Printf("a is int, value:%v\n", v)
    case map[string]int:
	fmt.Printf("a is map, value:%v\n", v)
    default:
	fmt.Println("不支持的类型")
    }
}
  • 3.既然所有类型都实现了空接口,那我们是否可以使用接口类型做判断,大胆尝试
package main

import "fmt"


func describe(a interface{})  {
    // 使用接口类型取值(可以取到)
    fmt.Println(a.(interface{}))
}

func main()  {
    inta := 65
    describe(inta)  // 65

    type Stu struct {
        Name string
        Age int
    }

    var stu = Stu{
        Name: "小亮",
        Age:  23,
    }
    describe(stu)  // {小亮 23}

    var m map[string]int
    describe(m)  // map[]
}
  • 4.接口类型断言
package main

import "fmt"

type Animal interface {
    Eat()
}

type Dog struct {
}

func (d Dog) Eat() {
    fmt.Println("小狗正在啃骨头")
}

type Cat struct {
}

func (c *Cat) Eat() {
    fmt.Println("小猫正在吃鱼")
}

func main()  {
    var dog Dog
    var cat Cat

    describe(dog)
    describe(cat)
}

func describe(a Animal)  {
    switch v := a.(type) {
    case Dog:
	fmt.Printf("a is dog, value: %v\n", v)  // a is dog, value: {}
    case Cat:
	fmt.Printf("a is cat, value: %v\n", v)  // a is cat, value: {}
    default:
	fmt.Println("不支持的类型")
    }
}

3.指针接收和值接收区别

1.值类型

  • 值类型实现的接口,指针类型可以存储进去
package main

import "fmt"

type Animal interface {
    Eat()
}

type Dog struct {
    Name string
}

// 值类型实现Dog对象方法  ------>  引用类型实现  fun(d *Dog)
func (d Dog) Eat() {
    fmt.Printf("小狗%s正在啃骨头\n", d.Name)
}

func main()  {
    var a Animal

    // Dog值类型实现了Eat方法,所以可以直接调用
    dog := Dog{Name: "小花"}
    a = dog
    a.Eat()

    // Dog引用类型没有实现Eat方法,为什么也可以调用Eat方法
    dog1 := &Dog{Name: "小黄"}
    a = dog1
    a.Eat()  // 首先从接口里面取出来是一个&Dog地址,然后将地址取值*Dog,找到对应的Eat接口方法,然后i调用
}

// 小狗小花正在啃骨头
// 小狗小黄正在啃骨头

2.指针类型

  • 指针类型实现的接口,值类型存储不进去
package main

import "fmt"

type Animal interface {
	Eat()
}

type Dog struct {
	Name string
}

func (d *Dog) Eat() {
	fmt.Printf("小狗%s正在啃骨头\n", d.Name)
}

func main()  {
    var a Animal

    //dog := Dog{Name: "小花"}
    /*
    假设a里面存储的是一个值类型的Dog,那么调用a.Eat的时候,由于指针类型实现了这个接口,
      则要先取a存储Dog的地址,获取到&Dog后,才可以调用
    总结:如果一个变量存储在接口类型的变量中之后,那么不能获取这个变量的地址

    //a = dog  // 报错,值类型的Dog没有实现Animal接口类型中的Eat方法
    //a.Eat()
    */

    dog1 := &Dog{Name: "小黄"}
    a = dog1
    a.Eat()
}

4.同一个类型(结构体)可以实现多个接口

  • 一个合格的程序员,可以使用gin|django|express|spring等框架进行开发
package main

import "fmt"

type Java interface {
    Spring()
}

type Python interface {
    Django()
}

type Node interface {
    Express()
}

type Go interface {
    Gin()
}

type Person struct {
}

func (p *Person) Spring() {
    fmt.Println("我会用java语言的spring框架写网站")
}

func (p *Person) Express() {
    fmt.Println("我会用node语言的express框架写网站")
}

func (p *Person) Django() {
    fmt.Println("我会用python语言的django框架写网站")
}

func (p *Person) Gin() {
    fmt.Println("我会用Go语言的gin框架写网站")
}

func main()  {
    var java Java  // nil
    var python Python  // nil
    var g Go  // nil
    var node Node  nil

    var p Person
    java = &p
    java.Spring()

    python = &p
    python.Django()

    g = &p
    g.Gin()

    node = &p  
    node.Express()
}

5.接口嵌套

package main

import "fmt"

type Java interface {
    Spring()
}

type Python interface {
    Django()
}

type Node interface {
    Express()
}

type Go interface {
    Gin()
}

type SeniorEngineer interface {  // 高级工程师
    Java
    Python
    Node
    Go
}

type MidLevelEngineer interface {  // 中级工程师
	Go
    Java
}

type JuniorEngineer interface {  // 初级工程师
    Python
}

type Person struct {
}

func (p *Person) Spring() {
    fmt.Println("我会用java语言的spring框架写网站")
}

func (p *Person) Express() {
    fmt.Println("我会用node语言的express框架写网站")
}

func (p *Person) Django() {
    fmt.Println("我会用python语言的django框架写网站")
}

func (p *Person) Gin() {
    fmt.Println("我会用Go语言的gin框架写网站")
}

func main()  {
    fmt.Println("-------------------高级工程师-------------------")
    var p Person
    var sen SeniorEngineer
    sen = &p
    sen.Express()
    sen.Gin()
    sen.Django()
    sen.Spring()

    fmt.Println("-------------------中级工程师-------------------")
    var mid MidLevelEngineer
    mid = &p
    mid.Spring()
    mid.Gin()

    fmt.Println("-------------------初级工程师-------------------")
    var jun JuniorEngineer
    jun = &p
    jun.Django()
}

/*
-------------------高级工程师-------------------
我会用node语言的express框架写网站
我会用Go语言的gin框架写网站
我会用python语言的django框架写网站
我会用java语言的spring框架写网站
-------------------中级工程师-------------------
我会用java语言的spring框架写网站
我会用Go语言的gin框架写网站
-------------------初级工程师-------------------
我会用python语言的django框架写网站
*/

6.多态

1.表现形式

package main

import "fmt"

type Code string
type Programmer interface {
    WriteHelloWorld() Code
}

type GoProgrammer struct {
}

func (p GoProgrammer) WriteHelloWorld() Code {
    return "fmt.Println(\"Hello World!\")"
}

type JavaProgrammer struct {
}

func (p JavaProgrammer) WriteHelloWorld() Code {
    return "System.out.Println(\"Hello World!\")"
}


// 统一入口
func writeFirstProgram(p Programmer)  {
    // Programmer是一个interface对象,所以其实例只能是指针类型
    fmt.Printf("%T %v\n", p, p.WriteHelloWorld())
}


func main()  {  
    writeFirstProgram(new(GoProgrammer))
    writeFirstProgram(new(JavaProgrammer))
}

7.注意

  • interface类型对应的实例只能是指针类型
posted @ 2022-09-23 17:30  fatpuffer  阅读(58)  评论(0)    收藏  举报