Go语言空接口用法汇总(附带实例)
Go语言中的空接口类型是指在接口中没有任何函数,用“interface{}”表示。
因为在空接口中没有任何函数,所以任何类型的变量都可以实现空接口。也正因为如此,在实际开发过程中,开发者既可以使用空接口保存任何类型的值,又可以从空接口中获取任何类型的值。
【实例 1】使用空接口保存基础类型变量的值。
声明空接口后,在 main() 函数中声明空接口变量,格式化输出空接口变量的值及其类型。分别声明初始值为 711 的 int 类型变量、初始值为“hello, go”的 string 类型变量,以及初始值为 true 的 bool 类型变量,把这 3 个变量的值依次赋值给空接口变量,并格式化输出此时空接口变量的值及其类型。代码如下:
空接口不仅可以保存基础变量的值,还能保存切片类型的数据、映射类型的数据和结构体中字段类型的数据。具体的使用方式如下:
下例演示如何保存切片类型的数据、映射类型的数据和结构体中字段类型的数据。
【实例 2】空接口类型的切片、映射和结构体中的字段。
初始化空接口类型的切片,切片中的数据为 123、hello 和 true;初始化空接口类型的映射,映射的值为“map[price:15 product:cap]”;声明表示汽车的结构体,其中包含一个表示价格的空接口类型字段,依次把 159800 和“壹拾伍万玖仟捌佰圆整”赋值给这个字段。代码如下:
初始化一个值为 711 的 int 类型变量 num,再初始化一个空接口变量,把变量 num 的值赋给这个空接口变量,接着直接从空接口中获取值,并将其赋给 int 类型变量 value,打印 int 类型变量 value 的值。代码如下:
把变量 num 的值赋给空接口变量 nf 后,虽然空接口变量 nf 的值是 int 类型,但是变量 nf 的数据类型仍然是空接口类型,这就是出现编译错误的原因。
下面使用“类型断言”修改第8行代码,代码如下:
1) 当空接口类型是基础类型、数组类型或结构体类型时,不论空接口的类型是否相同,都可以比较空接口保存的值。
先声明一个空接口变量 num,设置它的初始值为 11,再声明一个空接口变量 str,设置它的初始值为“hello”,接着分别打印这两个空接口变量的值及其数据类型,使用“==”运算符比较这两个空接口变量的值。代码如下:
2) 如果空接口类型是切片类型或映射类型,则无法比较空接口保存的值。
声明空接口变量 sl_1,设置它的初始值为包含 5 个元素的 int 类型切片,再声明一个空接口变量 sl_2,设置它的初始值为包含 10 个元素的 int 类型切片,使用“==”运算符比较这两个空接口变量的值。代码如下:
因为在空接口中没有任何函数,所以任何类型的变量都可以实现空接口。也正因为如此,在实际开发过程中,开发者既可以使用空接口保存任何类型的值,又可以从空接口中获取任何类型的值。
使用空接口保存值
空接口变量在没有被赋值的情况下,它的值及其数据类型都是 nil。对空接口变量执行赋值操作,空接口变量的值及其数据类型将发生变化。【实例 1】使用空接口保存基础类型变量的值。
声明空接口后,在 main() 函数中声明空接口变量,格式化输出空接口变量的值及其类型。分别声明初始值为 711 的 int 类型变量、初始值为“hello, go”的 string 类型变量,以及初始值为 true 的 bool 类型变量,把这 3 个变量的值依次赋值给空接口变量,并格式化输出此时空接口变量的值及其类型。代码如下:
package main //声明 main 包 import "fmt" //导入 fmt 包,用于打印字符串 type noFunctions interface{} //声明空接口 func main() { //声明 main()函数 var nf noFunctions //声明空接口变量 fmt.Printf("空接口保存的值:%v,空接口的类型:%T\n", nf, nf) //打印空接口变量的值及其类型 num := 711 //声明初始值为 711 的 int 类型变量 num nf = num //把变量 num 的值赋值给空接口变量 nf fmt.Printf("空接口保存的值:%v,空接口的类型:%T\n", nf, nf) //打印空接口变量的值及其类型 str := "hello, go" //声明初始值为"hello, go"的 string 类型变量 str nf = str //把变量 str 的值赋给空接口变量 nf fmt.Printf("空接口保存的值:%v,空接口的类型:%T\n", nf, nf) //打印空接口变量的值及其类型 b := true //声明初始值为 true 的 bool 类型变量 b nf = b //把变量 b 的值赋值给空接口变量 nf fmt.Printf("空接口保存的值:%v,空接口的类型:%T\n", nf, nf) //打印空接口变量的值及其类型 }运行结果如下:
空接口保存的值:<nil>,空接口的类型:<nil>
空接口保存的值:711,空接口的类型:int
空接口保存的值:hello, go,空接口的类型:string
空接口保存的值:true,空接口的类型:bool
空接口不仅可以保存基础变量的值,还能保存切片类型的数据、映射类型的数据和结构体中字段类型的数据。具体的使用方式如下:
- 当把切片类型设置为空接口类型时,这个切片可以保存不同类型的数据;
- 当把映射类型设置为空接口类型时,这个映射中所有与键对应的值都可以保存不同类型的数据;
- 当把结构体中某个字段的类型设置为空接口类型时,这个字段可以保存不同类型的数据。
下例演示如何保存切片类型的数据、映射类型的数据和结构体中字段类型的数据。
【实例 2】空接口类型的切片、映射和结构体中的字段。
初始化空接口类型的切片,切片中的数据为 123、hello 和 true;初始化空接口类型的映射,映射的值为“map[price:15 product:cap]”;声明表示汽车的结构体,其中包含一个表示价格的空接口类型字段,依次把 159800 和“壹拾伍万玖仟捌佰圆整”赋值给这个字段。代码如下:
package main //声明 main 包 import "fmt" //导入 fmt 包,用于打印字符串 func main() { //声明 main()函数 s := []interface{}{123, "hello", true} //初始化空接口类型的切片 fmt.Printf("切片中的数据:%v\n", s) //打印切片中的数据 m := map[string]interface{}{} //初始化空接口类型的映射 m["product"] = "cap" //初始化一组键值对,与键对应的值的类型是 string m["price"] = 15 //初始化一组键值对,与键对应的值的类型是 int fmt.Printf("集合中的数据:%v\n", m) //打印映射中的数据 var car struct { //声明一个表示汽车的结构体 price interface{} //声明表示价格的空接口类型字段 } car.price = 159800 //初始化字段的值,其类型是 int //打印结构体中的字段数据及其数据类型 fmt.Printf("结构体中的字段数据:%v,其数据类型:%T\n", car.price, car.price) car.price = "壹拾伍万玖仟捌佰圆整" //对字段重新赋值,其类型是 string //打印结构体中的字段数据及其数据类型 fmt.Printf("结构体中的字段数据:%v,其数据类型:%T\n", car.price, car.price) }运行结果如下:
切片中的数据:[123 hello true]
集合中的数据:map[price:15 product:cap]
结构体中的字段数据:159800,其数据类型:int
结构体中的字段数据:壹拾伍万玖仟捌佰圆整,其数据类型:string
从空接口中获取值
空接口变量被赋值后,如果直接从中获取这个值,并把它赋值给与其具有相同数据类型的另一个变量,将发生编译错误。初始化一个值为 711 的 int 类型变量 num,再初始化一个空接口变量,把变量 num 的值赋给这个空接口变量,接着直接从空接口中获取值,并将其赋给 int 类型变量 value,打印 int 类型变量 value 的值。代码如下:
package main //声明 main 包 import "fmt" //导入 fmt 包,用于打印字符串 func main() { //声明 main()函数 num := 711 //初始化值为 711 的 int 类型变量 num var nf interface{} = num //初始化空接口变量,把变量 num 的值赋给这个空接口变量 var value int = nf //直接从空接口中获取值,并将其赋给 int 类型变量 value fmt.Printf("value = %v\n", value) //打印 int 类型变量 value 的值 }上述代码编写时,会出现编译错误。把鼠标光标移至第 8 行代码的方框处,编译器弹出如下图所示的报错信息。

把变量 num 的值赋给空接口变量 nf 后,虽然空接口变量 nf 的值是 int 类型,但是变量 nf 的数据类型仍然是空接口类型,这就是出现编译错误的原因。
下面使用“类型断言”修改第8行代码,代码如下:
var value int = nf.(int)
比较空接口保存的值
使用空接口保存不同的值后,可以使用“==”运算符比较。在比较空接口保存的值时,需要注意以下几个问题。1) 当空接口类型是基础类型、数组类型或结构体类型时,不论空接口的类型是否相同,都可以比较空接口保存的值。
先声明一个空接口变量 num,设置它的初始值为 11,再声明一个空接口变量 str,设置它的初始值为“hello”,接着分别打印这两个空接口变量的值及其数据类型,使用“==”运算符比较这两个空接口变量的值。代码如下:
package main //声明 main 包 import "fmt" //导入 fmt 包,用于打印字符串 func main() { //声明 main()函数 var num interface{} = 11 //声明空接口变量 num,设置初始值为 11 //打印变量 num 的值及其数据类型 fmt.Printf("空接口变量 num 的值:%v,其数据类型:%T\n", num, num) var str interface{} = "hello" //声明空接口变量 str,设置初始值为 hello //打印变量 str 的值及其数据类型 fmt.Printf("空接口变量 str 的值:%v,其数据类型:%T\n", str, str) fmt.Println("num 和 str 的比较结果:", num == str) //打印对空接口保存的值进行比较后的结果 }运行结果为:
空接口变量 num 的值:11,其数据类型:int
空接口变量 str 的值:hello,其数据类型:string
num 和 str 的比较结果:false
2) 如果空接口类型是切片类型或映射类型,则无法比较空接口保存的值。
声明空接口变量 sl_1,设置它的初始值为包含 5 个元素的 int 类型切片,再声明一个空接口变量 sl_2,设置它的初始值为包含 10 个元素的 int 类型切片,使用“==”运算符比较这两个空接口变量的值。代码如下:
package main //声明 main 包 import "fmt" //导入 fmt 包,用于打印字符串 func main() { //声明 main()函数 //声明空接口变量 sl_1,设置初始值为包含 5 个元素的 int 类型切片 var sl_1 interface{} = []int{5} //声明空接口变量 sl_2,设置初始值为包含 10 个元素的 int 类型切片 var sl_2 interface{} = []int{10} fmt.Println("sl_1 == sl_2") //打印比较空接口保存的值之后的结果 }运行结果为:
panic: runtime error: comparing uncomparable type []int
运行结果是运行时错误,提示 int 类型的切片(即“[]int”)是不可比较的类型。