概述
interface 是一个定义了方法签名的集合,用来指定对象的行为,如果对象做到了Interfac中方法集定义的行为,那就可以说实现了Interface。
声明
接口的声明使用 interface 关键字 。
接口按照约定只包含一个方法的,接口的名字由方法名加 [e]r 后缀组成,例如 Printer、Reader、Writer、Logger、Converter 等等。还有一些不常用的方式(当后缀 er 不合适时),比如 Recoverable,此时接口名以 able 结尾,或者以 I 开头(像 .NET 或 Java 中那样)。
- 只要某个类型拥有该接口的所有方法签名,即算实现该接口,无需显示声明实现了哪个接口。
- 接口只有方法声明,没有实现,没有数据字段。
- 接口可以匿名嵌入其他接口,或嵌入结构中。
/* define an interface */
type interface_name interface {
method_name1 [return_type]
method_name2 [return_type]
method_name3 [return_type]
...
method_namen [return_type]
}
/* define a struct */
type struct_name struct {
/* variables */
}
/* implement interface methods*/
func (struct_name_variable struct_name) method_name1() [return_type] {
/* method implementation */
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {
/* method implementation */
}
空接口
没有任何方法的接口,我们称之为空接口。所以任何类型都实现了空接口,空接口表示为:
interface {
}
空接口用途
1 GO语言没有泛型,如果一个函数需要接收任意类型的参数, 则参数类型可以使用空接口类型,这是弥补没有泛型的一种手段。
空接口和反射
空接口是反射实现的基础 ,反射库就是将相关具体的类型转换并赋值给空接口后才去处理。
空接口和nil
空接口有两个字段, 一个是实例类型,另 一个是指向绑定实例的指针,只有两个都为nil时 ,空接口才为nil。
指针接收和值接收
TypeAssertion
判断接口变量的的具体类型,需要使用到类型断言type assertion。它的语法是:
变量名称.(数据类型)
判断当前的a的数据类型是字符串,如果当前a不是字符串使用下面写法会引起panic
func printStr(a interface{}){
fmt.Println(a.(string))
}
func main() {
a := 10
printStr(a)
}
为了避免 panic 错误发生,可以通过如下操作来进行断言检查,断言会返回一个bool类型的参数 告诉是否断言的类型是否真的匹配
t, ok := i.(T)
断言成功,ok 的值为 true,断言失败 t 值为T类型的默认值,也不会引起panic。如下
func printStr(a interface{}){
if v, ok := a.(string); ok {
fmt.Println(v)
}else {
fmt.Println("不是字符 无法打印")
}
}
func main() {
a := 10
printStr(a)
printStr("test")
}
TypeSwitch
另外一种判断interface变量的具体类型,那就是利用 switch 语句。
func printValue(v interface{}) {
switch v := v.(type) {
case string:
fmt.Printf("%v is a string\n", v)
case int:
fmt.Printf("%v is an int\n", v)
default:
fmt.Printf("The type of v is unknown\n")
}
}
func main() {
v := 10
printValue(v)
s := "test"
printValue(s)
}
编译期间判断是否实现了某个接口
var _ Pooler = new(WeightedRoundRobin)
Pooler是一个接口类型。
type Pooler interface {
// ...
}
如果说次接口没有被实现,ide会有红横线出现,另一方面在编译的时候会出现报错。两方面的提示来保证写底层代码的接口是有被实现的。
接口类型&nil
package main
import "fmt"
type Foo interface {
bar()
}
type FooType struct {
}
func (f FooType)bar(){
fmt.Println("hello world")
}
func main() {
var f Foo
fmt.Println(f==nil)
fmt.Printf("%T %v\n",f,f)
var t *FooType
fmt.Println(t==nil)
fmt.Printf("%T %v\n",t,t)
f = t
fmt.Println(f==nil)
fmt.Printf("%T %v\n",f,f)
}
打印结果
true
<nil> <nil>
true
*main.FooType <nil>
false
*main.FooType <nil>
自动检测类型是否实现接口
package main
type Foo interface {
bar()
}
type FooType struct {
}
//func (f FooType)bar(){
// fmt.Println("hello world")
//}
func main() {
var _ Foo = (*FooType)(nil)
}
参考
https://blog.csdn.net/tomatomas/article/details/95880842
https://blog.keyboardman.me/2018/05/12/nil-in-go/
https://www.jianshu.com/p/dd80f6be7969