Go 使用接口

Go 使用接口,在Go语言中,接口指定了一个方法集,这是实现模块化的强大方式。您可将接口视为方法集的蓝本,它描述了方法集中的所有方法,但没有实现它们。接口功能强大,因为它充当了方法集规范,这意味着可在符合接口要求的前提下随便更换实现。

接口描述了方法集中的所有方法,并指定了每个方法的函数签名。下面的示例假设需要编写一些控制机器人(Robot)的代码。粗略地说,可假定有多种类型的机器人,控制这些机器人行为的方式存在细微的差别。给定这个编程任务,您可能认为需要为每种机器人编写不同的代码。通过使用接口,可将代码重用于有相同行为的实体。就这个机器人示例而言,下面的接口描述了开关机器人的方式。

type Robot interface {
PowerOn() err
}

接口Robot只包含一个方法——PowerOn。这个接口描述了方法PowerOn的函数签名:不接受任何参数且返回一种错误类型。从高级层面说,接口还有助于理解代码设计。在无须关心实现的情况下,很容易理解设计是什么样的。

那么如何使用接口呢?接口是方法集的蓝本,要使用接口,必须先实现它。如果代码满足了接口的要求,就实现了接口。要实现接口Robot,可声明一个满足其要求的方法集。

type T850 struct {
Name string
}

func (a *T850) PowerOn() err {
return nil
}

这个实现很简单,但满足了接口Robot的要求,因为它包含方法PowerOn,且这个方法的函数签名与接口Robot要求的一致。接口的强大之处在于,它们支持多种实现。例如,您也可以像下面这样来实现接口Robot。

type R2D2 struct {
Broken bool
}

func (r *R2D2) PowerOn() err {
if r.Broken {
return errors.New("R2D2 is broken")
} else {
return nil
}
}

这也满足了接口Robot的要求,因为它符合这个方法集的定义——包含方法PowerOn,同时函数签名也相同。请注意,这里与方法集相关联的结构体为R2D2,它包含的数据字段与T850不同,方法PowerOn的代码也完全不同,但函数签名一样。

要满足接口的要求,只要实现了它指定的方法集,且函数签名正确无误就可以了。

当前,接口Robot有两种实现,虽然有相同的Robot定义很有用,但没有可同时用于T850和R2D2实例的代码。接口也是一种类型,可作为参数传递给函数,因此可编写可重用于多个接口实现的函数。

例如,编写一个可用于启动任何机器人的函数。

func Boot(r Robot) error {
return r.PowerOn()
}

这个函数将接口Robot的实现作为参数,并返回调用方法PowerOn的结果。这个函数可用于启动任何机器人,而不管其方法PowerOn是如何实现的。T850和R2D2都可利用这个方法。

如下程序是一个完整的使用接口Robot的示例。

 package main

 import (
  "errors"
  "fmt"
 )

 type Robot interface {
  PowerOn() error
 }

 type T850 struct {
  Name string
 }

 func (a *T850) PowerOn() error {
  return nil
 }

 type R2D2 struct {
  Broken bool
 }

 func (r *R2D2) PowerOn() error {
  if r.Broken {
   return errors.New("R2D2 is broken")
  } else {
   return nil
  }
 }

 func Boot(r Robot) error {
return r.PowerOn()
 }

 func main() {
  t := T850{
   Name:  "The Terminator",
  }

  r := R2D2{
   Broken:  true,
  }

  err := Boot(&r)

  if err != nil {
   fmt.Println(err)
  } else {
   fmt.Println("Robot is powered on!")
  }

  err = Boot(&t)

  if err != nil {
   fmt.Println(err)
  } else {
   fmt.Println("Robot is powered on!")
  }
 }

执行结果:
Go 使用接口

注意:Go语言是面向对象的吗?

对结构体和方法有基本认识后,如果您熟悉其他语言,可能会问:Go是面向对象的吗?面向对象编程是这样一种编程范式:使用具有特定行为的对象来建立数据模型。通常,面向对象语言提供允许一种对象继承另一种对象的功能。虽然Go语言没有提供类和类继承等面向对象功能,但结构体和方法集弥补了这部分不足,提供了一些面向对象元素。由此可以说Go在不使用类和继承的情况下提供了类似于面向对象编程的功能,虽然这一点还存在争议。

乍一看,接口提供的抽象层可能有点复杂,但它有助于代码重用,还能够让您完全更换实现。假设要编写一个使用MySQL数据库的计算机程序,如果不使用接口,则代码将完全是针对MySQL的。在这种情况下,如果后来要将MySQL数据库换成其他数据库,如PostgreSQL,就可能需要重写大量的代码。

通过定义一个数据库接口,该接口的实现将比使用的数据库更重要。从理论上说,只要实现满足接口的要求,就可使用任何数据库,因此可轻松地更换数据库。数据库接口可包含多个实现,这就引入了多态的概念。

多态意味着多种形式,它让接口能够有多种实现。在Go语言中,接口以声明的方式提供了多态,因为接口描述了必须提供的方法集以及这些方法的函数签名。如果一个方法集实现了一个接口,就可以说它与另一个实现了该接口的方法集互为多态。编译器也会验证接口:检查方法集并确保接口确实是多态的。通过将接口正式化,可确保接口的两种实现是多态的。这无疑会让代码可验证、可测试且是灵活的。

酷客教程相关文章:

赞(0)

评论 抢沙发

评论前必须登录!