2024-09-28 · 4 min read
断断续续地在看 Go 语言的语法,看到空接口这块,感觉有些意思,记录一下。
Go 语言中空接口的表示方式是 interface{}
,它最大的作用就是可以存储任意类型的值,可以理解为 TypeScript 中的 any
。
作为一个前端开发,Go 中这种表示任意类型的方式让我觉得有些怪异,但它确实是很有用的。比如我想存储一组用户信息,但具体多少信息是不确定的,我希望可以无限被扩展,那我可以这样写:
func main() {
userInfo := make(map[string]interface{}) // 信息的值是可以任意类型的
userInfo["name"] = "Tom"
userInfo["isAdmin"] = true
userInfo["age"] = 18
userInfo["hobby"] = []string{"reading", "running"}
}
如果不使用空接口,那么我可能需要定义一个结构体来存储这些信息:
type UserInfo struct {
name string
isAdmin bool
age int
hobby []string
}
func main() {
userInfo := UserInfo{
name: "Tom",
isAdmin: true,
age: 18,
hobby: []string{"reading", "running"},
}
}
这样每当我想要新增一个字段,就需要去结构体中添加一个字段类型,虽说加类型不算什么大问题,但无法做到添加未知类型的字段。所以空接口的作用在这个场景下就体现出来了。其实空接口在 Go 标准库的源码中也是被大量使用的。
说到空接口,那不得不提下类型断言,一些被定义为空接口的值,如果想要访问其身上的特定方法时,就必须要用到类型断言。
还是上面的例子,如果想要访问 hobby
中的第一个值,我们的直觉应该是通过索引去访问,如:
func main() {
userInfo := make(map[string]interface{})
userInfo["hobby"] = []string{"reading", "running"}
fmt.Println(userInfo["hobby"][0]) // 通过索引访问
}
但这样写是错误的,会报错 invalid operation: cannot index userInfo["hobby"] (map index expression of type interface{})
。
其实仔细想想也很正常,userInfo["hobby"]
可能是任意一种类型的值,它不一定具备索引访问的特性。所以这里就需要用到类型断言,必须先断言出它的具体类型,才可以去访问它的值。
不过 Go 中的类型断言写法,也是让我觉得有点怪异,写法是 n.(type)
,n 代表要断言的变量,type 代表断言的类型。如上我想要获取 hobby
中的第一个值,可以这样写:
v, ok := userInfo["hobby"].([]string)
if ok {
fmt.Println(v[0])
} else {
fmt.Println("no hobby")
}
这样写可能看着有些繁琐,但确实能提高程序的健壮性,作为初学者,我只能去适应接受。
结尾也没啥好说的,以上只是简单记录以下的空接口以及类型断言的使用,希望以后能更好的理解它们的作用。
不得不说,作为前端去学习 Go 语言,还是处处充满着不适应。那为什么要学呢?后面有空我还是想单独说说这个话题,这里就不多哔哔了。