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在不使用类和继承的情况下提供了类似于面向对象编程的功能,虽然这一点还存在争议。
乍一看,接口提供的抽象层可能有点复杂,但它有助于代码重用,还能够让您完全更换实现。假设要编写一个使用MySQL数据库的计算机程序,如果不使用接口,则代码将完全是针对MySQL的。在这种情况下,如果后来要将MySQL数据库换成其他数据库,如PostgreSQL,就可能需要重写大量的代码。
通过定义一个数据库接口,该接口的实现将比使用的数据库更重要。从理论上说,只要实现满足接口的要求,就可使用任何数据库,因此可轻松地更换数据库。数据库接口可包含多个实现,这就引入了多态的概念。
多态意味着多种形式,它让接口能够有多种实现。在Go语言中,接口以声明的方式提供了多态,因为接口描述了必须提供的方法集以及这些方法的函数签名。如果一个方法集实现了一个接口,就可以说它与另一个实现了该接口的方法集互为多态。编译器也会验证接口:检查方法集并确保接口确实是多态的。通过将接口正式化,可确保接口的两种实现是多态的。这无疑会让代码可验证、可测试且是灵活的。
酷客教程相关文章:
评论前必须登录!
注册