go语言中的反射

空接口可以存储任意类型的变量,如何知道这个空接口保存数据的类型是什么?值是什么呢?

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

posted @ 2026-10-09 09:03  何人陪我共长生  阅读(65)  评论(0)    收藏  举报