本文正在参加金石计划

「前语」

什么是接口

接口是一种标准化的约好或标准,它规则了两个个别之间怎样进行通讯和交互。

假定你要与一个陌生人攀谈,你可能需求恪守一些根本的礼仪标准,比如问候、介绍自己、交换名片等等。这些标准能够协助你和陌生人之间建立信任和合作关系,同时也确保了沟通的顺畅和准确。

在实践编程中,完成一个接口一般需求完成接口界说的一切办法,以确保目标能够被正确运用和调用。这也意味着接口能够被用来强制标准目标的行为,以确保它们契合特定的要求和标准。

接口是一种笼统的工具,由于它并不关心详细的完成细节,而只重视于目标或类应该完成的办法或功用。

假定你正在编写一个程序,需求处理一些动物目标,比如狗、猫、鸟等等。你能够界说一个名为“动物”的接口,它规则了这些目标应该完成哪些办法,比如“吃饭”、“睡觉”、“叫声”等等。这些办法仅仅描绘了动物应该具有的行为,而并不关心这些行为怎样被完成。不同的动物能够根据自己的特点来完成这些办法,比如狗可能会发出“汪汪”声,而猫则可能会发出“喵喵”声。

总的来说,接口是一种有必要恪守的约好与标准,这使得两个个别之间的交互得到了确保,而且其笼统的特性,又是标准具有灵活性而不用恪守死规矩。

怎样声明一个接口

接口类型的界说一般由一组办法签名组成,这些办法签名界说了接口的行为标准。如下:

type Greeter interface{
  Greet() string
}
interface{
  Add() int
}

这儿咱们声明晰两个接口类型,其间一个名为Greeter,它里面有一个办法名为Greet,回来类型为string的办法签名;别的一个接口它没有类型名,因而它是匿名接口,其内部有一个办法名为Add,回来值类型为int的办法签名。

与结构体类似的,接口也答应嵌套,比如如下:

type Adder interface{
  Add(int, int) int
}
type Subtractor interface{
  Sub(int, int) int
}
type Calculator interface{
  Adder
  Subtractor
}

在这个比如中,咱们声明晰三个接口,分别是AdderSubtractor与嵌套了前面两者的CalCulatorAdder接口中有一个名为Add,参数类型为两个int类型,回来值类型为int类型的办法签名;Subtractor接口中有一个名为Sub,参数类型为两个int类型,回来值类型为int类型的办法签名。

怎样初始化一个接口变量

完成接口

接口没有被完成,那它是没有含义的,因而运用接口的第一步应该是先完成它:

type Cal struct{}
func (c Cal) Add(i1, i2 int) int {
	return i1 + i2
}
func (c Cal) Sub(i1, i2 int) int {
	return i1 - i2
}

Go的接口是隐式完成的,只需详细类型的办法集是接口办法的超集,就代表该类型完成了接口。

接口初始化

单纯的声明一个接口变量没有任何含义,接口只有被初始化为详细的类型是才有含义。其初始化条件同样契合「变量」赋值条件的根本逻辑,但是接口的初始化愈加简略,由于只需右值的办法集是左值的超集就能赋值:

  1. 用结构体赋值

    var c Calculator
    c = Cal{}
    
  2. 用接口变量赋值

    var c2 Calculator = Cal{}
    var s Subtractor = c2
    

接口有什么用

举一个Gin框架路由的比如:

// IRouter defines all router handle interface includes single and group router.
type IRouter interface {
	IRoutes
	Group(string, ...HandlerFunc) *RouterGroup
}
// IRoutes defines all router handle interface.
type IRoutes interface {
	Use(...HandlerFunc) IRoutes
	Handle(string, string, ...HandlerFunc) IRoutes
	Any(string, ...HandlerFunc) IRoutes
	GET(string, ...HandlerFunc) IRoutes
	POST(string, ...HandlerFunc) IRoutes
	DELETE(string, ...HandlerFunc) IRoutes
	PATCH(string, ...HandlerFunc) IRoutes
	PUT(string, ...HandlerFunc) IRoutes
	OPTIONS(string, ...HandlerFunc) IRoutes
	HEAD(string, ...HandlerFunc) IRoutes
	Match([]string, string, ...HandlerFunc) IRoutes
	StaticFile(string, string) IRoutes
	StaticFileFS(string, string, http.FileSystem) IRoutes
	Static(string, string) IRoutes
	StaticFS(string, http.FileSystem) IRoutes
}
// RouterGroup is used internally to configure router, a RouterGroup is associated with
// a prefix and an array of handlers (middleware).
type RouterGroup struct {
	Handlers HandlersChain
	basePath string
	engine   *Engine
	root     bool
}
api := engine.Group("/api/v1")
api.GET("/tags", tag.List)

以上代码有两个接口,分别是IRouterIRoutes,还有一个结构体RouterGroupengine.Group办法将会创立一个RouterGroup,并将其赋值给apiapi的逻辑含义就是作为“/api/v1”则个组,后面再增加的途径,比如说“api/v1/test”或许“api/v1/t/a”之类的一切子途径都在api这个组别下。而且RouterGroup通过姓名能够看出它的语义就是一个路由组,而它不光完成了IRouter,称为一个根途径,而且还完成了IRoutes,使其能够直接绑定子路由。

通过接口,不光让RouterGroup具有IRouterIRoutes两种状况,还制定了Router的处理标准与标准,这就是接口最大的含义——多态性、标准化