golang interface理解

最早对interface的认知比较片面,很多人都说interface与channel是go语言的灵魂。然而在工作中使用的机会比较少,发现自己对interface的理解太片面。下面就记录并总结下go中的interface。

interface是个啥

go程序设计中是这样解释的“接口是一种抽象类型,他并没有暴露所包含数据的布局或者内部结构,当然也没有那些数据的基本操作,它所提供的仅仅是一些方法而已”。根据上面的说明我们可以提炼出接口是对一些方法的封装
很多的C++程序员吐槽go不便之处就是没有’泛型’我们没法使用模板啊,go语言中确实没有,但是go提供了interface让我们可以实现这种泛型。正如上面所说interface是一种抽象类型,是一组方法的集合,我们可以把它看成一种定义内部方法的动态数据类型,任意实现了这些方法的数据类型都可以认为是特定的数据类型。(是不是有点像是C++中模板类)。
正如sort包中

package sort

// A type, typically a collection, that satisfies sort.Interface can be
// sorted by the routines in this package. The methods require that the
// elements of the collection be enumerated by an integer index.
type Interface interface {
    // Len is the number of elements in the collection.
    Len() int
    // Less reports whether the element with
    // index i should sort before the element with index j.
    Less(i, j int) bool
    // Swap swaps the elements with indexes i and j.
    Swap(i, j int)
}

在sort包中提供了三个方法,只要我们实现了这三个方法我们就可以对任何的类型进行排序。
看过了官方的sort是如何写的我们也自己动手写一个例子

package main

import "fmt"

type classmate struct {
    class uint32
    grade uint32
    age   uint32
    name  string
}

type info interface {
    Len() int
    Compare(agex,agei uint32)uint32
}

type listInfo []classmate
type listuint []uint32

func (this listInfo)Len()(int){
    return len(this)
}

func (this listInfo)Compare(i,j uint32)(uint32){
    if this[i].grade > this[j].grade{
        return this[i].grade
    }
    return this[j].grade
}

func (this listuint)Len()(int){
    return len(this)
}

func (this listuint)Compare(i,j uint32)(uint32){
    if this[i] > this[j]{
        return this[i]
    }
    return this[j]
}


func main(){
    lInfo := listInfo{
        classmate{1,1,6,"tom"},
        classmate{2,3,8,"jim"},
    }
    fmt.Println("len is ", lInfo.Len())
    garde := lInfo.Compare(0,1)
    fmt.Printf("grade is %d \n",garde)

    uInfo := listuint{9,6,8}
    fmt.Println("len is ", uInfo.Len())
    fmt.Printf("compare is %d ",uInfo.Compare(1,2))
}

示例中我们的interface中包含了两个方法,len与compare,获取长度与比较大小,我们分别为不同的类型实现了接口中的方法,是不是有点像C++中的函数重载(C++中函数重载要求参数个数或者参数类型不同)。同时我们也发现我们为不同的类型实现了方法,所以说一个接口类型不会去关心到底是什么数据类型实现了他自身。接口类型的本质就是如果一个数据类型实现了自身的方法集,那么该接口类型变量就能够引用该数据类型的值。
在上面我们提到了sort包,我们只要实现了其提供的三个方法就可以对任何类型进行排序,因为我们实现了它的接口类型。

package main

import "fmt"

type classmate struct {
    class uint32
    grade uint32
    age   uint32
    name  string
}

type classinfo struct {
    total uint32
    grade uint32
}

type info interface {
    coutInfo()
    changeInfo(grade uint32)
}

func (this *classmate)coutInfo(){
    fmt.Println("info is ",this)
}

func (this *classmate)changeInfo(grade uint32){
    this.grade = grade
    fmt.Println("info is ",this)
}

func (this *classinfo)coutInfo(){
    fmt.Println("info is ",this)
}

func (this *classinfo)changeInfo(grade uint32){
    this.grade = grade
    fmt.Println("info is ",this)
}

func interTest(test info,grade uint32){
    test.coutInfo()
    test.changeInfo(grade)
}


func main(){
    mate := &classmate{
        class: 1,
        grade:1,
        age:6,
        name:"jim",
    }
    info := &classinfo{
        total:30,
        grade:5,
    }
    interTest(mate,3)
    interTest(info,8)
}

输出:

info is  &{1 1 6 jim}
info is  &{1 3 6 jim}
info is  &{30 5}
info is  &{30 8}

相信这个例子可以帮助我们更好的理解函数interTest的第一个输入参数并没有要求参数的具体类型,而是一个接口类型。

使用interface的注意事项

  1. 将对象赋值给接口变量时会复制该对象。
  2. 接口使用的是一个名为itab的结构体存储的
    type iface struct{
    tab *itab // 类型信息
    data unsafe.Pointer // 实际对象指针
    }
  3. 只有接口变量内部的两个指针都为nil的时候,接口才等于nil。
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页