当前位置 博文首页 > 详解Golang语言中的interface

    详解Golang语言中的interface

    作者:雨燕 时间:2021-02-04 06:12

    interface是一组method签名的组合,interface可以被任意对象实现,一个对象也可以实现多个interface。任意类型都实现了空interface(也就是包含0个method的interface),空interface可以存储任意类型的值。interface定义了一组方法,如果某个对象实现了某个接口的所有方法,则此对象就实现了此接口。

    go version go1.12

    package main
    
    import (
      "fmt"
    )
    
    // 定义struct
    type Human struct {
      name string
      age  int
      phone string
    }
    type Student struct {
      Human // 匿名字段
      school string
      loan  float32
    }
    type Employee struct {
      Human  // 匿名字段
      company string
      money  float32
    }
    
    // Human对象实现SayHi()方法
    func (h Human) SayHi() {
      fmt.Printf("Hi, I am %s, you can call me on %s\n", h.name, h.phone)
    }
    
    // Human对象实现Sing()方法
    func (h Human) Sing(lyrics string) {
      fmt.Println("La la la...", lyrics)
    }
    
    // Human对象实现Guzzle()方法
    func (h Human) Guzzle(beerStein string) {
      fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
    }
    
    // Employee对象重写SayHi()方法
    func (e Employee) SayHi() {
      fmt.Printf("Hi I am %s, I work at %s. Call me on %s\n", e.name, e.company, e.phone)
    }
    
    // Student对象实现BorrowMoney()方法
    func (s Student) BorrowMoney(amount float32) {
      s.loan += amount
    }
    
    // Employee对象实现SpendSalary()方法
    func (e Employee) SpendSalary(amount float32) {
      e.money -= amount
    }
    
    // 定义interface,interface是一组method签名的组合
    // interface可以被任意对象实现,一个对象也可以实现多个interface
    // 任意类型都实现了空interface(也就是包含0个method的interface)
    // 空interface可以存储任意类型的值
    // interface Men的3个method被Human,Student,Employee实现,也就是这3个对象都实现了interface Men。即:
    // interface定义了一组方法,如果某个对象实现了某个接口的所有方法,则此对象就实现了此接口。
    type Men interface {
      SayHi()
      Sing(lyrice string)
      Guzzle(beerStein string)
    }
    
    // interface YoungChap的BorrowMoney() method只被Student对象实现,也就是只有Student实现了YoungChap
    type YoungChap interface {
      SayHi()
      Sing(song string)
      BorrowMoney(amount float32)
    }
    
    // interface ElderlyGent的SpendSalary() method只被Employee对象实现,也就是只有Employee实现了ElderlyGent
    type ElderlyGent interface {
      SayHi()
      Sing(song string)
      SpendSalary(amount float32)
    }
    
    func main() {
      // 定义Student类型的变量
      lucy := Student{Human{"lucy", 19, "10086"}, "tsinghua", 100.00}
      lily := Student{Human{"lily", 19, "10086"}, "tsinghua", 100.00}
      liming := Student{Human{"liming", 19, "10086"}, "tsinghua", 100.00}
      // 定义Employee类型的变量
      tom := Employee{Human{"tom", 29, "10000"}, "Google", 200.00}
      // 定义Men类型的变量i
      var i Men
      // i存储Student
      i = lucy
      fmt.Println("This is lucy, a student:")
      i.SayHi()
      i.Sing("Happy Birthday")
      i.Guzzle("Ha ha ha...")
    
      // i存储Employee
      i = tom
      fmt.Println("This is tom, an Employee:")
      i.SayHi()
    
      // 定义slice Men,包含Men类型元素的切片,这个slice可以被赋予实现了Men接口的任意结构的对象
      fmt.Println("Let's use a slice of Men and see what happens:")
      x := make([]Men, 3)
      // 三个不同类型(不同Method)的元素,实现了同一个interface(Men)
      x[0], x[1], x[2] = lucy, lily, liming
      for _, value := range x {
        value.SayHi()
      }
    }

    函数参数

    interface接口还可以作为函数参数,因为interface的变量可以持有任意实现该interface类型的对象,我们可以通过定义interface参数,让函数接受各种类型的参数。 判断interface变量存储的元素的类型,目前常用的有两种方法:Comma-ok断言和switch测试。

    go version go1.12

    /**
     * interface接口作为函数参数
     * 判断interface变量存储的元素的类型
     */
    package main
    
    import (
      "fmt"
      "strconv"
    )
    
    // 定义Human对象
    type Human struct {
      name string
      age  int 
      phone string
    }
    
    // 定义空接口
    type Element interface{}
    
    // 定义切片
    type List []Element
    
    // 定义Person对象
    type Person struct {
      name string
      age int 
    }
    
    // 通过定义interface参数,让函数接受各种类型的参数
    // 通过这个Method(方法),Human对象实现了fmt.Stringer接口
    // Stringer接口是fmt.Println()的参数,最终使得Human对象可以作为fmt.Println的参数被调用
    func (h Human) String() string {
      return "<" + h.name + " - " + strconv.Itoa(h.age) + " years - phone: " + h.phone + ">" 
    }
    
    // 通过定义interface参数,让函数接受各种类型的参数
    // 通过这个Method(方法),Person对象实现了fmt.Stringer接口
    // Stringer接口是fmt.Println()的参数,最终使得Person对象可以作为fmt.Println的参数被调用
    func (p Person) String() string {
      return "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
    }
    
    func main() {
      // interface作为函数的参数传递
      Lucy := Human{"Lucy", 29, "10086"}
      fmt.Println("This human is:", Lucy)
    
      list := make(List, 3)
      list[0] = 100
      list[1] = "Hello Golang!"
      list[2] = Person{"Lily", 19}
    
      // Comma-ok断言
      for index, element := range list {
        // 判断变量的类型 格式:value, ok = element(T)
        // value是interface变量的值,ok是bool类型,element是interface的变量,T是断言的interface变量的类型
        if value, ok := element.(int); ok {
          fmt.Printf("list[%d] is an int and it's value is %d\n", index, value)
        } else if value, ok := element.(string); ok {
          fmt.Printf("list[%d] is a string and it's value is %s\n", index, value)
        } else if value, ok := element.(Person); ok {
          fmt.Printf("list[%d] is a Person and it's value is %s\n", index, value)
        } else {
          fmt.Printf("list[%d] is a different type\n", index)
        }
      }
    
      // switch
      for index, element := range list {
        // 注意:element.(type)语法不能在switch外的任何逻辑中使用
        switch value := element.(type) {
        case int:
          fmt.Printf("list[%d] is an int, it's value is %d\n", index, value)
        case string:
          fmt.Printf("list[%d] is a string, it's value is %s\n", index, value)
        case Person:
          fmt.Printf("list[%d] is a Person, it's value is %s\n", index, value)
        default:
          fmt.Printf("list[%d] is a differernt type", index)
        }
      }
    }
    js
    下一篇:没有了