go语言 | 图解反射(一)

反射

反射是指在程序运行期对程序本身进行访问和修改的能力

变量的内在机制

变量包含类型信息和值信息 var arr [10]int arr[0] = 10

类型信息:是静态的元信息,是预先定义好的

值信息:是程序运行过程中动态改变的

反射的使用

reflect包封装了反射相关的方法

获取类型信息:reflect.TypeOf,是静态的

获取值信息:reflect.ValueOf,是动态的

示例1

go 复制代码
package main

import (
	"fmt"
	"reflect"
)

type User struct {
	Name string
	Age  int
}

func main() {
	u := User{"tom", 27}

	// 获取类型的具体信息
	t := reflect.TypeOf(u)
	fmt.Println(t.Name()) // User
	fmt.Println(t.Kind()) // struct
	v := reflect.ValueOf(u)
	fmt.Println(v)
}

输出:

bash 复制代码
User
struct
{tom 27}

示例2

反射可以在运行时动态获取程序的各种详细信息

反射获取interface类型信息

go 复制代码
package main

import (
	"fmt"
	"reflect"
)

//反射获取interface类型信息

func reflect_type(a interface{}) {
	t := reflect.TypeOf(a)
	fmt.Println("类型是:", t)
	// kind()可以获取具体类型
	k := t.Kind()
	fmt.Println(k)
	switch k {
	case reflect.Float64:
		fmt.Printf("a is float64\n")
	case reflect.String:
		fmt.Println("string")
	}
}

func main() {
	var x float64 = 3.4
	reflect_type(x)
}

输出

bash 复制代码
类型是: float64
float64
a is float64

示例3

反射获取interface值信息

go 复制代码
package main

import (
	"fmt"
	"reflect"
)

//反射获取interface值信息

func reflect_value(a interface{}) {
	v := reflect.ValueOf(a)
	fmt.Println(v)
	k := v.Kind()
	fmt.Println(k)
	switch k {
	case reflect.Float64:
		fmt.Println("a是:", v.Float())
	}
}

func main() {
	var x float64 = 3.4
	reflect_value(x)
}

输出

bash 复制代码
3.4
float64
a是: 3.4

示例4

反射修改值信息

go 复制代码
package main

import (
	"fmt"
	"reflect"
)

// 反射修改值
func reflect_set_value(a interface{}) {
	v := reflect.ValueOf(a)
	k := v.Kind()
	switch k {
	case reflect.Float64:
		// 反射修改值
		v.SetFloat(6.9)
		fmt.Println("a is ", v.Float())
	case reflect.Ptr:
		// Elem()获取地址指向的值
		v.Elem().SetFloat(7.9)
		fmt.Println("case:", v.Elem().Float())
		// 地址
		fmt.Println(v.Pointer())
	}
}

func main() {
	var x float64 = 3.4
	fmt.Println("main:", x)
	// 反射认为下面是指针类型,不是float类型
	reflect_set_value(&x)
	fmt.Println("main:", x)
}

输出

bash 复制代码
main: 3.4
case: 7.9
1374390181912
main: 7.9

示例5

查看类型、字段和方法

go 复制代码
package main

import (
	"fmt"
	"reflect"
)

// 定义结构体
type User struct {
	Id   int
	Name string
	Age  int
}

// 绑方法
func (u User) Hello() {
	fmt.Println("Hello")
}

// 传入interface{}
func Poni(o interface{}) {
	t := reflect.TypeOf(o)
	fmt.Println("类型:", t)
	fmt.Println("字符串类型:", t.Name())
	// 获取值
	v := reflect.ValueOf(o)
	fmt.Println(v)
	// 可以获取所有属性
	// 获取结构体字段个数:t.NumField()
	for i := 0; i < t.NumField(); i++ {
		// 取每个字段
		f := t.Field(i)
		fmt.Printf("%s : %v", f.Name, f.Type)
		// 获取字段的值信息
		// Interface():获取字段对应的值
		val := v.Field(i).Interface()
		fmt.Println("val :", val)
	}
	fmt.Println("=================方法====================")
	for i := 0; i < t.NumMethod(); i++ {
		m := t.Method(i)
		fmt.Println(m.Name)
		fmt.Println(m.Type)
	}

}

func main() {
	u := User{1, "zs", 20}
	Poni(u)
}

输出

bash 复制代码
类型: main.User
字符串类型: User
{1 zs 20}
Id : intval : 1
Name : stringval : zs
Age : intval : 20
=================方法====================
Hello
func(main.User)

示例6

查看匿名字段

go 复制代码
package main

import (
    "fmt"
    "reflect"
)

// 定义结构体
type User struct {
    Id   int
    Name string
    Age  int
}

// 匿名字段
type Boy struct {
    User
    Addr string
}

func main() {
    m := Boy{User{1, "zs", 20}, "bj"}
    t := reflect.TypeOf(m)
    fmt.Println(t)
    // Anonymous:匿名
    fmt.Printf("%#v\n", t.Field(0))
    // 值信息
    fmt.Printf("%#v\n", reflect.ValueOf(m).Field(0))
}

输出

bash 复制代码
main.Boy
reflect.StructField{Name:"User", PkgPath:"", Type:(*reflect.rtype)(0x102b8b100), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:true}
main.User{Id:1, Name:"zs", Age:20}

示例7

修改结构体的值

go 复制代码
package main

import (
    "fmt"
    "reflect"
)

// 定义结构体
type User struct {
    Id   int
    Name string
    Age  int
}

// 修改结构体值
func SetValue(o interface{}) {
    v := reflect.ValueOf(o)
    // 获取指针指向的元素
    v = v.Elem()
    // 取字段
    f := v.FieldByName("Name")
    if f.Kind() == reflect.String {
        f.SetString("kuteng")
    }
}

func main() {
    u := User{1, "5lmh.com", 20}
    SetValue(&u)
    fmt.Println(u)
}

输出

bash 复制代码
{1 kuteng 20}

示例8

调用方法

go 复制代码
package main

import (
	"fmt"
	"reflect"
)

// 定义结构体
type User struct {
	Id   int
	Name string
	Age  int
}

func (u User) Hello(name string) {
	fmt.Println("Hello:", name)
}

func main() {
	u := User{1, "5lmh.com", 20}
	v := reflect.ValueOf(u)
	// 获取方法
	m := v.MethodByName("Hello")
	// 构建一些参数
	args := []reflect.Value{reflect.ValueOf("6666")}
	// 没参数的情况下:var args2 []reflect.Value
	// 调用方法,需要传入方法的参数
	m.Call(args)
}

输出

bash 复制代码
Hello: 6666

示例9

获取字段的tag

go 复制代码
package main

import (
    "fmt"
    "reflect"
)

type Student struct {
    Name string `json:"name1" db:"name2"`
}

func main() {
    var s Student
    v := reflect.ValueOf(&s)
    // 类型
    t := v.Type()
    // 获取字段
    f := t.Elem().Field(0)
    fmt.Println(f.Tag.Get("json"))
    fmt.Println(f.Tag.Get("db"))
}

输出

bash 复制代码
name1
name2

参考

https://www.topgoer.com/常用标准库/反射.html

相关推荐
笃励19 分钟前
Java面试题二
java·开发语言·python
jyan_敬言28 分钟前
【Linux】Linux命令与操作详解(一)文件管理(文件命令)、用户与用户组管理(创建、删除用户/组)
linux·运维·服务器·c语言·开发语言·汇编·c++
FL162386312931 分钟前
[C#]C# winform部署yolov11-pose姿态估计onnx模型
开发语言·yolo·c#
笑非不退42 分钟前
C++ 异步编程 并发编程技术
开发语言·c++
爱写代码的刚子1 小时前
C++知识总结
java·开发语言·c++
martian6651 小时前
QT开发:基于Qt实现的交通信号灯模拟器:实现一个带有倒计时功能的图形界面应用
开发语言·qt
冷琴19961 小时前
基于java+springboot的酒店预定网站、酒店客房管理系统
java·开发语言·spring boot
缘友一世1 小时前
macOS .bash_profile配置文件优化记录
开发语言·macos·bash
tekin2 小时前
macos 中使用macport安装,配置,切换多版本php,使用port 安装php扩展方法总结
开发语言·macos·php·port·mac多版本php安装管理·port-select
CSXB992 小时前
一、Python(介绍、环境搭建)
开发语言·python·测试工具·集成测试