本文主要介绍Galang的接口编程

接口介绍

接口类型是对其他类型行为的概括与抽象。通过接口,我们可以写出更加灵活和通用的函数,这些函数不用绑定在一个特定的类型实现上。

GoLang的接口的独特之处在于它是隐式实现,对于一个具体的类型,无须声明它实现了哪些接口,只要提供接口所必需的方法就行。

一个接口类型定义了一套方法,如果一个具体类型要实现该接口,那么必须实现接口类型定义中的所有方法。

//定义一个接口,里面为一个方法

type Interface interface {

  SetName(name string)

}

//定义一个实现该接口的结构

type UserInfo struct {

  Username string

}

func (u *UserInfo) SetName(name string) { //指针方法

  u.Username = name

}

//主函数测试

func main() {

  var userinfo UserInfo//声明一下结构体

  var userInterface Interface = &userinfo//由于结构体实现对应接口,因此可以赋值,另外方法中用了指针,因此在 
                                         //赋值时需要使用地址。

  userInterface.SetName("test")//利用接口调用方法进行赋值

  fmt.Println(userinfo.Username)

}

接口组合

  1. 一个类型可以实现多个接口。

  2. 接口可以相互组合成为新的接口。

例如:

type Writer interface {

  write()

}

type Reader interface {

  read()

}

//组合接口

type ReadWriter interface {

  Writer

  Reader

}

//类型实现了上面三个接口

type User struct{

  Username string

}

func (u *User) wirte() {}

func (u *User) read() {}

接口实际用法

接口主要是用于泛型编程,可以通用一些操作。

尽量在仅有两个或者多个具体类型需要按统一的方式处理时才需要接口。

例如:一个数字z,需要一个公式计算它,z*z + 10。

我们可以把z的平方单独出来给数字定义一个方法,然后再把整个公式放入一个通用函数中。

例如:

//定义一个平方接口

type Arithmetic interface {

  Square() int

}

//定义一个实现该接口的结构

type Number struct {

  z int

}

func (number *Number) Square() int {

  return number.z * number.z

}

//定义一个公用函数,利用接口的泛型编程通用化公式

func CommonFormula(a Arithmetic) int {

  return a.Square() + 10

}

//主函数实现

func main(){

  number := Number{

    z: 5,

  }

  c := CommonFormula(&number)

  fmt.Println(c)

}

 

类型断言

类型断言是一个作用在接口值上的操作,写出来类似于x.(T),其中x是一个接口类型的表达式,T是一个类型(称为断言类型)

func assert(i interface{}) {

  s := i.(string)

  fmt.Println(s)

}

func main() {

  var s interface{} = "aaaaa"

  assert(s)

}

如果上述 var s interface{} = "aaaaa" 写成 = 123,则会触发panic:

interface conversion: interface {} is int, not string

使用 v, ok := i.(T) 解决该问题,如果接口i的具体类型是T,则v将具有i的实际值,ok为 true。

如果接口i的具体类型不是T,则ok为 false,v为T的零值,但程序不会触发 panic。

 

类型分支

类型分支用来将一个接口的具体类型与多个case语句指定的类型进行比较。在类型断言 i.(T)中,将类型T替换为关键字 type就变成了 type switch。

func findType(i interface{}) {

  switch i.(type) {

    case string:

      fmt.Printf("I am a string and my value is %s\n", i.(string))

    case int:

      fmt.Printf("I am an int and my value is %d\n", i.(int))

    default:

      fmt.Printf("Unknown type\n")

  }

}

func main() {

  findType("test")

  findType(23)

  findType(123.321)

}