Golang接口及其类型检查
一、接口及接口实现
接口简介:Java、Go中的接口及其使用简介_玉言心的博客-CSDN博客_java接口和go接口
-
Golang接口定义 - 接口即约定【简单理解】
type Writer interface {} // 空接口 type Writer interface { // 带有方法的接口 Write(p []byte)(err error) }
-
Golang接口实现
type ByteWriter struct{} func (b *ByteWriter) Write(p []byte)(err error){ if len(p) <= 0{ return errors.New("err") } // 其他操作 return nil }
二、interface与其他变量等价判断
-
interface类型变量与非interface类型变量判等时
- 首先要求非interface类型实现了接口,否则编译不通过
- 如果是空接口,则可以认为所有类型都实现了该接口
- interface类型变量的动态类型、值均与非interface类型变量相同时,两个变量判等结果为true
-
例如下列代码:
首先,m的默认类型是一个空接口,因此可以认为int类型已经实现了接口,所以不会出现编译报错问题
其次,p == m进行毕竟判断时,由于interface是基于动态派发的,具体类型(身份)是根据实现类型来确定具体类型的,又p和m均是int数组类型,因此类型相同,结合数组的初始化方式,我们也易知p和m的值相等,因此输出结果为true。
package main import "fmt" func main() { var p [100]int var m interface{} = [...]int{99: 0} fmt.Println(p == m) }
-
interface类型变量与interface类型变量判等时
- 会同时比较两个接口变量的type和value,都相等的时候,才会认为相等
-
例如下列代码:
type A interface{} type B struct{} var a *B print(a == nil) //true nil代表接口类型的zero value print(a == (*B)(nil)) //true print((A)(a) == (*B)(nil)) //true print((A)(a) == nil) //false
- 最后一个之所以是false,是因为只有当一个interface的value和type都unset的时候,它才等于nil,而上述代码中的interface
(A)a
的type是*B
, 不是unset。【结合下文】
- 最后一个之所以是false,是因为只有当一个interface的value和type都unset的时候,它才等于nil,而上述代码中的interface
三、nil关键字和类型断言
-
nil
nil
其实甚至不是golang的关键词,只是一个变量名。定义在 buildin/buildin.go 中// nil is a predeclared identifier representing the zero value for a // pointer, channel, func, interface, map, or slice type. var nil Type // Type must be a pointer, channel, func, interface, map, or slice type // Type is here for the purposes of documentation only. It is a stand-in // for any Go type, but represents the same type for any given function // invocation. type Type int
-
golang中nil代表了
pointer
,channel
,func
,interface
,map
或者slice
的zero value,比如:n1 := (*struct{})(nil) // 指针 fmt.Printf("(*struct{})(nil) nil: %t ,type is: %s\n", n1 == nil, reflect.TypeOf(n1).String()) n2 := []int(nil) // 切片 fmt.Printf("[]int(nil) nil: %t ,type is: %s\n", n2 == nil, reflect.TypeOf(n2).String()) n3 := map[int]bool(nil) // map fmt.Printf("map[int]bool(nil) nil: %t ,type is: %s\n", n3 == nil, reflect.TypeOf(n3).String())
输出结果: (*struct{})(nil) nil: true ,type is: *struct {} []int(nil) nil: true ,type is: []int map[int]bool(nil) nil: true ,type is: map[int]bool
-
特别是在interface中,只有当一个interface的V和T都unset时,它的值才是nil,
-
-
类型断言
-
作用和语法格式
1.作用:是一个接口表达式,作用于接口上的操作,用来检查作为操作数的动态类型是否满足指定的断言类型。 2.语法:x.(T),x是接口类型的表达式,T是一个断言类型,如果T是具体类型,会检查x的动态类型是否就是T,如果检查成功,断言结果就是x的动态值,类型就是T,否正操作失败;如果T是接口类型,会检查x的动态类型是否就是T,如果检查成功,动态值并没有提取出来,结果仍然是一个接口值,接口值的类型type和值value部分不变,结果类型是接口类型T。
-
示例
type Cat struct{ Name string } func main(){ var in interface{} = &Cat{ Name: "cici" } switch in.(type){ case *Cat: // 其他操作 } }
-
四、拓展:var _ interface = (*type)(nil)
-
作用:和类型断言类似,用来检查类型type这个struct是否实现了interface 这个接口
-
理解:可以把=左右两边分开来看
- 左边:
var _ interface
等价于我们平时用的var variable type
- 右边:
(* type)(nil)
等价于var variable *type nil
- 左边:
-
因此,可以直接理解为var _ interface = (*type)(nil)就是用来检查type是否实现了接口interface
-
例子:
type Writer interface { // 带有方法的接口 Write(p []byte)(err error) ToString() string } var _ Writer = (*ByteWriter)(nil) type ByteWriter struct{} func (b *ByteWriter) Write(p []byte)(err error){ if len(p) <= 0{ return errors.New("err") } // 其他操作 return nil }
-
我们为Writer接口新增方法ToString,返回一个string类型的值,然后使用var _ Writer = (*ByteWriter)(nil)进行检查,由于ByteWriter仅仅实现了方法Write,没有实现ToString,因此会报:
Cannot use '(*ByteWriter)(nil)' (type *ByteWriter) as the type Writer Type does not implement 'Writer' as some methods are missing: ToString() string
从而提示用户还有ToString() string没有实现
-