空接口可以存储任意类型的变量,如何知道这个空接口保存数据的类型是什么?值是什么呢?
1、可以使类型断言
2、可以使用反射实现,也就是在程序运行时动态的获取一个变量的类型信息和值信息。
反射的基本介绍
反射是指在程序运行期间对程序本身进行访问和修改的能力。
正常情况程序在编译时,变量被转换为内存地址,
变量名不会被编译器写入到可执行部分。
在运行程序时,程序无法获取自身的信息。
支持反射的语言可以在程序编译期将变量的反射信息,
如字段名称、类型信息、结构体信息等整合到可执行文件中,并给程序提供接口访问反射信息,
这样就可以在程序运行期获取类型的反射信息,并且有能力修改它们。
go语言中反射可以实现的功能
1、反射可以在程序运行期间动态的获取变量的各种信息,比如变量的类型类别
2、如果是结构体,通过反射还可以获取结构体本身的信息,比如结构体的字段、结构体的方法。
3、通过反射,可以修改变量的值,可以调用关联的方法
go语言中的变量是分为两部分的:
变量的类型信息:预先定义好的元信息。
值信息:程序运行过程中可动态变化的。
在Go语言的反射机制中,任何接口值都由是一个具体类型和具体类型的值两部分组成的。
在Go语言中反射的相关功能由内置的
在Go语言中反射的相关功能由内置的 reflect包提供。
任意接口值在反射中都可以理解为由reflect.Type和reflect.Value 两部分组成,
并且 reflect 包提供了reflect.TypeOf和reflect.ValueOf
两个重要函数来获取任意对象的Value和Type。
reflect.TypeOf()获取任意值的类型对象
在Go语言中,使用 reflect.TypeOf() 函数可以接受任意interface{}参数,
可以获得任意值的类型对象(reflect.Type),
程序通过类型对象可以访问任意值的类型信息。
通过反射获取变量的类型信息
package main
import (
"fmt"
"reflect"
)
// 通过反射来获取变量的类型
func GetVarType(v interface{}) {
vType := reflect.TypeOf(v)
fmt.Printf("变量的类型是:%v\n", vType)
}
func main() {
var a int = 100
GetVarType(a)
var b string = "hello"
GetVarType(b)
}
变量的类型是:int
变量的类型是:string
通过反射获取结构体的类型信息
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int
}
// 通过反射来获取变量的类型
func GetVarType(v interface{}) {
vType := reflect.TypeOf(v)
fmt.Printf("变量的类型是:%v\n", vType)
}
func main() {
var p Person = Person{
Name: "张三",
Age: 18,
}
GetVarType(p)
}
输出: 变量的类型是:main.Person
type Name 和 type Kind
在反射中关于类型还划分为两种:类型(Type)和种类(Kind)。
因为在Go语言中我们可以使用type关键字构造很多自定义类型,
而种类(Kind)就是指底层的类型,
但在反射中,当需要区分指针、结构体等大品种的类型时,就会用到种类(Kind)。
举个例子,我们定义了结构体类型,通过反射查看它的类型和种类。
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int
}
// 通过反射来获取变量的类型
func GetVarType(v interface{}) {
vType := reflect.TypeOf(v)
// v.Name() 获取类型名称
// v.Kind() 获取类型种类
fmt.Printf("变量的类型是:%v\n", vType)
fmt.Printf("结构体的名称是:%v\n", vType.Name())
fmt.Printf("结构体的种类是:%v\n", vType.Kind())
}
func main() {
var p Person = Person{
Name: "张三",
Age: 18,
}
GetVarType(p)
}
变量的类型是:main.Person
结构体的名称是:Person
结构体的种类是:struct
reflect.ValueOf()
reflect.ValueOf()返回的是reflect.Value类型,其中包含了原始值的值信息。
reflect.Value与原始值之间可以互相转换。
通过反射获取变量的值信息
package main
import (
"fmt"
"reflect"
)
// 通过反射来获取变量的类型
func GetVarType(v interface{}) {
// 通过反射来获取变量的值信息
value := reflect.ValueOf(v)
fmt.Printf("value = %v\n", value)
}
func main() {
var a = 10
GetVarType(a)
}
value = 10
为啥会直接报错呢
package main
import (
"fmt"
)
// 通过反射来获取变量的类型
func GetVarType(v interface{}) {
var num = v + 10 // 为啥会报错呢
fmt.Printf("num = %v\n", num)
}
func main() {
var a = 10
GetVarType(a)
}
因为:v 的类型是 interface{}(空接口),不是 int。
正确做法一:类型断言;方法二:通过反射获取变量的值信息
func GetVarType(v interface{}) {
// 把它转换为 int 类型,再进行加法操作
num := v.(int) + 10
fmt.Printf("num = %v\n", num)
}
通过反射获取变量的原始值信息,然后进行相加
package main
import (
"fmt"
"reflect"
)
// 通过反射来获取变量的类型
func GetVarType(v interface{}) {
// 通过反射来获取变量的值信息
value := reflect.ValueOf(v)
// value.Int() 反射获取变量的原始值
var sum = value.Int() + 10
fmt.Printf("sum = %v\n", sum)
}
func main() {
var a = 10
GetVarType(a)
}
通过反射获取变量的类型,通过switch语句判断变量的类型是哪种
package main
import (
"fmt"
"reflect"
)
// 通过反射来获取变量的类型
func GetVarType(v interface{}) {
// 通过反射来获取变量的值信息
value := reflect.ValueOf(v)
kind := value.Kind()
switch kind {
// int 类型
case reflect.Int64:
fmt.Printf("int64类型\n")
// float32 类型
case reflect.Float32:
fmt.Printf("float32类型\n")
// string 类型
case reflect.String:
fmt.Printf("string类型\n")
// 其他类型
default:
fmt.Printf("其他类型\n")
}
}
func main() {
var a float32 = 10.14
var b int64 = 100
var c string = "hello"
GetVarType(a)
GetVarType(b)
GetVarType(c)
}
直接修改会报错的哈
package main
import ("fmt")
func reflectSetValue1(x interface{}){
// 直接修改的话会报错的哈
// 报错信息:cannot indirect x (variable of type interface{})
*x = 100
}
func main() {
var a int = 10
reflectSetValue1(&a)
fmt.Printf("a的值是 %v\n",a)
}
报错: cannot indirect x (variable of type interface{})
通过反射来修改值
package main
import ("fmt")
import "reflect"
func reflectSetValue1(x interface{}){
v := reflect.ValueOf(x)
// 输出的是: ptr 表示是指针
fmt.Println(v.Kind())
// 输出的是: int64 表示是int类型
fmt.Println(v.Elem().Kind())
// 判断是否是int64类型
if v.Elem().Kind() == reflect.Int64{
// 设置值
v.Elem().SetInt(20)
}
}
func main() {
var a int64 = 10
reflectSetValue1(&a)
fmt.Printf("a的值是 %v\n",a)
}
ptr
int64
a的值是 20