Go语言接口的定义和使用
Go 语言提供了一种称为接口(interface)的数据类型,它代表一组方法的集合。接口的组合、嵌套和鸭子类型(Duck Typing)等实现了代码复用、解耦和模块化等特性,而且接口是方法动态分派、反射的基础功能。
接口设计是非侵入式的,接口设计者无须知道接口被哪些类型实现。而接口使用者只需知道实现怎样的接口,无须指明实现哪一个接口。编译器在编译时就会知道哪个类型实现哪个接口,或者接口应该由谁来实现。
非侵入式设计是 Go 语言设计者经过多年的大项目经验总结出来的设计之道,让接口和实现者真正解耦,编译速度才能真正提高,同时降低项目之间的耦合度。
接口是双方约定的一种合作协议,它是一种类型,也是一种抽象结构,不会暴露所含数据格式、类型及结构。
接口语法定义如下:
2)接口里面的 method1、method2、…、methodN 代表方法名;parameter 代表参数名称和数据类型,如果方法没有参数,则无须设置;returnType 代表返回值的数据类型,如果方法没有返回值,则无须设置。
3)当接口方法的首个字母是大写格式,并且接口的首个字母也是大写格式时,将接口和方法设为导出标识符,它们可以被其他 go 文件访问。
根据接口语法定义,在同一接口定义不同类型的方法,示例如下:
接口方法只需设置方法名称、参数名称和数据类型、返回值的数据类型,无须在接口中编写方法的业务功能,而方法的业务功能由结构体方法实现,示例如下:
1) 定义接口 actions 和结构体 cats,接口 actions 分别设置 4 个方法:walk()、runs()、speak() 和 rest();结构体 cats 只设置成员 name,其数据类型为字符串类型。
2) 结构体 cats 定义 4 个方法,每个方法分别对应接口 actions 的方法,也就是接口 actions 的方法通过结构体方法实现具体功能逻辑。将结构体绑定接口,结构体必须为接口中的每个方法定义相应的结构体方法,否则程序提示 as some methods are missing 异常。
3) 主函数 main() 定义接口变量 a,将结构体 cats 实例化生成实例化变量 c;然后把变量 c 的内存地址赋值给变量 a,结构体 cats 绑定在接口变量 a 中。
4) 如果结构体方法的接收者是值接收者,只要把实例化变量 c 赋值给变量 a 即可,接口变量 a 或结构体实例化变量 c 都可以调用接口方法。
运行上述代码,运行结果如下图所示。
综上所述,接口的定义与使用总结如下:
接口设计是非侵入式的,接口设计者无须知道接口被哪些类型实现。而接口使用者只需知道实现怎样的接口,无须指明实现哪一个接口。编译器在编译时就会知道哪个类型实现哪个接口,或者接口应该由谁来实现。
非侵入式设计是 Go 语言设计者经过多年的大项目经验总结出来的设计之道,让接口和实现者真正解耦,编译速度才能真正提高,同时降低项目之间的耦合度。
接口是双方约定的一种合作协议,它是一种类型,也是一种抽象结构,不会暴露所含数据格式、类型及结构。
接口语法定义如下:
type interface_name interface { method1(parameter) [returnType] method2(parameter) [returnType] method3(parameter) [returnType] ... methodN(parameter) [returnType] }1)接口使用关键字 type 定义;关键字 type 后面设置接口名称 interface_name;接口名称后面设置接口类型 interface,interface 是 Go 语言的关键字。
2)接口里面的 method1、method2、…、methodN 代表方法名;parameter 代表参数名称和数据类型,如果方法没有参数,则无须设置;returnType 代表返回值的数据类型,如果方法没有返回值,则无须设置。
3)当接口方法的首个字母是大写格式,并且接口的首个字母也是大写格式时,将接口和方法设为导出标识符,它们可以被其他 go 文件访问。
根据接口语法定义,在同一接口定义不同类型的方法,示例如下:
type actions interface { // 没有参数,也没有返回值 walk() // 没有参数,有返回值 runs() (int, int) // 有参数,没有返回值 speak(content string, speed int) // 有参数,也有返回值 rest(sleepTime int) (int) }
接口方法只需设置方法名称、参数名称和数据类型、返回值的数据类型,无须在接口中编写方法的业务功能,而方法的业务功能由结构体方法实现,示例如下:
package main import "fmt" // 定义接口 type actions interface { // 没有参数,也没有返回值 walk() // 没有参数,有返回值 runs() (int, int) // 有参数,没有返回值 speak(content string, speed int) // 有参数,也有返回值 rest(sleepTime int) int } // 定义结构体 type cats struct { name string } // 定义接口方法的功能逻辑 func (c *cats) walk() { fmt.Printf("%v在散步\n", c.name) } func (c *cats) runs() (int, int) { fmt.Printf("%v在跑步\n", c.name) speed := 10 time := 1 return speed, time } func (c *cats) speak(content string, speed int) { fmt.Printf("%v在说话:%v,语速:%v\n", c.name, content, speed) } func (c *cats) rest(sleepTime int) int { fmt.Printf("%v在休息,入睡时间:%v小时\n", c.name, sleepTime) return sleepTime } func main() { // 定义接口变量 var a actions // 结构体实例化 c := cats{name: "kitty"} // 结构体实例化变量的指针赋值给接口变量 a = &c // 调用接口中的方法 a.walk() speed, time := a.runs() fmt.Printf("跑步速度:%v,跑步时间:%v\n", speed, time) a.speak("喵喵", 2) sleepTime := a.rest(10) fmt.Printf("入睡时间:%v小时\n", sleepTime) }上述代码的实现过程说明如下:
1) 定义接口 actions 和结构体 cats,接口 actions 分别设置 4 个方法:walk()、runs()、speak() 和 rest();结构体 cats 只设置成员 name,其数据类型为字符串类型。
2) 结构体 cats 定义 4 个方法,每个方法分别对应接口 actions 的方法,也就是接口 actions 的方法通过结构体方法实现具体功能逻辑。将结构体绑定接口,结构体必须为接口中的每个方法定义相应的结构体方法,否则程序提示 as some methods are missing 异常。
3) 主函数 main() 定义接口变量 a,将结构体 cats 实例化生成实例化变量 c;然后把变量 c 的内存地址赋值给变量 a,结构体 cats 绑定在接口变量 a 中。
4) 如果结构体方法的接收者是值接收者,只要把实例化变量 c 赋值给变量 a 即可,接口变量 a 或结构体实例化变量 c 都可以调用接口方法。
运行上述代码,运行结果如下图所示。
kitty在散步
kitty在跑步
跑步速度:10,跑步时间:1
kitty在说话:喵喵,语速:2
kitty在休息,入睡时间:10小时
入睡时间:10小时
综上所述,接口的定义与使用总结如下:
- 接口是使用关键字 type 和 interface 定义的,接口方法只需设置方法名称、参数及其数据类型、返回值的数据类型。
- 接口方法的功能逻辑由结构体方法实现,接口无法单独使用,它必须与结构体组合使用。
- 使用接口必须创建接口变量和实例化结构体,然后将结构体实例化变量或变量的内存地址赋值给接口变量,完成结构体与接口的绑定。
- 接口变量只能调用接口中定义的方法,结构体实例化变量不仅能调用接口方法,还能调用接口之外的结构体方法和结构体成员。
- 如果结构体绑定了接口,结构体必须为接口中的每个方法定义相应的结构体方法,否则程序提示 as some methods are missing 异常。