Golang 空接口 & 类型断言

空接口,是指没有定义任何方法的接口类型。

所以,任何类型,都可以被看作是实现了空接口,同理,空接口类型的变量,可以存储任意类型的( 接口 )值

func main() {
	var x any // 空接口类型的变量,可以存储任意类型的值

	x = 100
	fmt.Printf("type:%T value:%v \n", x, x) // type:int value:100
	x = "hello"
	fmt.Printf("type:%T value:%v \n", x, x) // type:string value:hello
	x = true
	fmt.Printf("type:%T value:%v \n", x, x) // type:bool value:true
	x = struct {
		Name string
	}{"小明"}
	fmt.Printf("type:%T value:%v \n", x, x) // type:struct { Name string } value:{小明}
}

type any interface {
	// 定义一个空接口
}

「 声明方式( 推荐 )」通常,在使用空接口类型时,不必使用 type 关键字,直接使用 interface{} 即可

var x interface{}  // 声明一个空接口类型变量x

「 应用 」简单来说就是,空接口,可以存储任意类型的值

// 空接口,作为函数参数,可以接收任意类型的数据
func show(a interface{}) {
	fmt.Printf("type:%T value:%v\n", a, a)
        // 问题是,接口值可能被赋值为任意类型的值,So,如何获取其具体存储的数据呢 ?
}

// 空接口,作为 map 的值,可以保持任意类型的值
	var stu = make(map[string]interface{})
	stu["name"] = "小明"
	stu["age"] = 20
	fmt.Println(stu)  // map[age:20 name:小明]

类型断言

所谓 “ 类型断言 ”,可以这样理解:接口值可能被赋值为任意类型的数据,而,Golang 中使用的是强类型,

  • 也就是说:接口值,由 “类型” 和 “值” 组成,这两部分会根据存入值的不同而发生变化

所以,我们在对接口值进行实际操作之前,通常需要对其进行 “类型判断”,才能进行后续的操作

// 基本语法

x.(T)   // x:表示接口类型的变量;T:表示断言 x 可能是的类型

// 代码示例
func main() {
	var x interface{}

	x = &Dog{"小白"}
	v, ok := x.(*Dog) // 返回两个参数,第一个参数是 x 转化为 T 类型后的变量
	// 第二个参数,是一个布尔值,若为true,则表示断言成功,为 false,则表示断言失败
	if ok {
		fmt.Println("断言成功")
		fmt.Println(v.Name) // 小白  // 结构体,才能如此调用
	} else {
		fmt.Println("断言失败")
	}
}

// 定义一个结构体
type Dog struct {
	Name string
}

如果对于一个接口值,有多个实际类型需要判断,可以使用 switch 语句

func justifyType(x interface{}) {
	switch v := x.(type) {
	case string:
		fmt.Printf("x is a string,value is %v\n", v)
	case int:
		fmt.Printf("x is a int is %v\n", v)
	case bool:
		fmt.Printf("x is a bool is %v\n", v)
	default:
		fmt.Println("unsupport type!")
	}
}