go语言接口与断言
Posted zpf253
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言接口与断言相关的知识,希望对你有一定的参考价值。
go语言接口与断言
类型
接口也是go语言中的一种类型,它能够出现在变量的定义、函数的入参和返回值中并对它们进行约束,不过go语言中有两种略微不同的接口,一种是带有一组方法的接口,另一种是不带任何方法的interface
go语言使用runtime.iface表示第一种接口,使用runtime.eface表示第二种不包含任何方法的interface,两种接口虽然都是用interface声明,但是由于后者在go语言中很常见,所以在实现时使用了特殊类型。
数据结构
// 没有方法的interface
type eface struct
_type *_type
data unsafe.Pointer
// 记录着Go语言中某个数据类型的基本特征
type _type struct
size uintptr
ptrdata uintptr // size of memory prefix holding all pointers
hash uint32
tflag tflag
align uint8
fieldAlign uint8
kind uint8
// function for comparing objects of this type
// (ptr to object A, ptr to object B) -> ==?
equal func(unsafe.Pointer, unsafe.Pointer) bool
// gcdata stores the GC type data for the garbage collector.
// If the KindGCProg bit is set in kind, gcdata is a GC program.
// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
gcdata *byte
str nameOff
ptrToThis typeOff
// 有方法的interface
type iface struct
tab *itab
data unsafe.Pointer
type itab struct
inter *interfacetype
_type *_type
hash uint32 // copy of _type.hash. Used for type switches.
_ [4]byte
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
// interface数据类型对应的type
type interfacetype struct
typ _type
pkgpath name
mhdr []imethod
eface结构体只包含指向底层数据和类型的两个指针,iface结构体有指向原始数据的指针data,但更重要的是runtime.itab类型的tab字段。
类型结构体
runtime._type是go语言类型的运行时表示。其中包含了很多类型的元信息,例如类型的大小、哈希、对齐以及种类。
- size字段存储了类型占用的内存空间,为内存空间的分配提供信息。
- hash字段能够帮助我们快速确定类型是否相等。
itab结构体
runtime.itab结构体是接口类型的核心组成部分,每一个runtime.itab都占32字节。我们可以将其看成接口类型和具体类型的组合,他们分别用inner和_type两个字段表示。
除inner和_type这两个用于表示类型的字段外,上述结构体中的另外两个字段也有自己的作用。
- hash是对_type.hash的复制,当我们想将interface类型转换成具体类型时,可以使用该字段快速判断目标类型和具体类型runtime._type是否一致。
- fun是一个动态大小的数组,它是一个用于动态派发的虚函数表,存储了一组函数指针。虽然该变量被声明成大小固定的数组,但在使用时会通过原始指针获取其中的数据,所以fun数组中保存的元素数量是不确定的。
go语言接口断言
接口断言
因为空接口 interface{}没有定义任何函数,因此 Go 中所有类型都实现了空接口。当一个函数的形参是interface{},那么在函数中,需要对形参进行断言,从而得到它的真实类型。
语法格式:
// 安全类型断言
<目标类型的值>,<布尔参数> := <表达式>.( 目标类型 )
//非安全类型断言
<目标类型的值> := <表达式>.( 目标类型 )
示例代码:
package main
import "fmt"
func main() {
var i1 interface{} = new (Student)
s := i1.(Student) //不安全,如果断言失败,会直接panic
fmt.Println(s)
var i2 interface{} = new(Student)
s, ok := i2.(Student) //安全,断言失败,也不会panic,只是ok的值为false
if ok {
fmt.Println(s)
}
}
type Student struct {
}
断言其实还有另一种形式,就是用在利用 switch语句判断接口的类型。每一个case会被顺序地考虑。当命中一个case 时,就会执行 case 中的语句,因此 case 语句的顺序是很重要的,因为很有可能会有多个 case匹配的情况。
示例代码:
switch ins:=s.(type) {
case Triangle:
fmt.Println("三角形。。。",ins.a,ins.b,ins.c)
case Circle:
fmt.Println("圆形。。。。",ins.radius)
case int:
fmt.Println("整型数据。。")
}
以上是关于go语言接口与断言的主要内容,如果未能解决你的问题,请参考以下文章