go语言 | 图解反射(一)

news/2024/5/19 4:01:02 标签: golang, 开发语言, 后端, 反射

反射

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

变量的内在机制

变量包含类型信息和值信息 var arr [10]int arr[0] = 10
类型信息:是静态的元信息,是预先定义好的
值信息:是程序运行过程中动态改变的

反射的使用

reflect包封装了反射相关的方法
获取类型信息:reflect.TypeOf,是静态的
获取值信息:reflect.ValueOf,是动态的

示例1

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)
}

输出:

User
struct
{tom 27}

示例2

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

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)
}

输出

类型是: float64
float64
a is float64

示例3

反射获取interface值信息

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)
}

输出

3.4
float64
a是: 3.4

示例4

反射修改值信息

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)
}

输出

main: 3.4
case: 7.9
1374390181912
main: 7.9

示例5

查看类型、字段和方法

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)
}

输出

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

示例6

查看匿名字段

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))
}

输出

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

修改结构体的值

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)
}

输出

{1 kuteng 20}

示例8

调用方法

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)
}

输出

Hello: 6666

示例9

获取字段的tag

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"))
}

输出

name1
name2

参考

https://www.topgoer.com/%E5%B8%B8%E7%94%A8%E6%A0%87%E5%87%86%E5%BA%93/%E5%8F%8D%E5%B0%84.html


http://www.niftyadmin.cn/n/5167332.html

相关文章

【Ruoyi管理后台】用户登录强制修改密码

近期有个需求&#xff0c;就是需要调整Ruoyi管理后台&#xff1a;用户如果三个月(长时间)未修改过密码&#xff0c;需要在登录时强制修改密码&#xff0c;否则不能登录系统。 一、后端项目调整 从需求来看&#xff0c;我们需要在用户表增加一个字段&#xff0c;用于标记用户最…

【紫光同创国产FPGA教程】——【PGL22G第九章】HDMI环路实验例程

本原创教程由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注明出处 适用于板卡型号&#xff1a; 紫光同创PGL22G开发平台&#xff08;盘古22K&#xff09; 一&#xff1a;盘古22K开发板&#xff08;紫光同创PGL22G开…

Godot Shader -变量的声明

变量的声明 uniform 可以将值传递给着色器。这些值对整个着色器来说是全局的,被称为 uniform。当一个着色器后来被分配给一个材质时,uniform 将作为可编辑的参数出现在其中。uniform 不能从着色器内部写入。 可以在材质编辑器的修改这些uniform的值,也可以通过 GDScript来…

react: zustand数据缓存

react状态库包括 zustand、Redux、Valtio、Jotai 和 Recoil。 定义和使用 // main.ts import ./store// store/index.ts import { create } from zustand const useStore create((set) > ({bears: 1,increasePopulation: () > set((state: any) > ({ bears: state.be…

【PostgreSql本地备份为dump文件与恢复】使用脚本一键备份为dump文件

环境&#xff1a;windows数据库&#xff1a;postgresql 1.准备脚本 backUpDb.bat 脚本为备份脚本&#xff0c;双击运行&#xff0c;右键可以选择编辑&#xff1b;restoreDb.bat 脚本为恢复脚本&#xff0c;双击运行&#xff0c;右键选择编辑&#xff1b; 1.1 脚本介绍 如上图…

如何改变Wi-Fi的IP地址,提高网络连接稳定性和速度

Wi-Fi已经成为我们日常生活中必不可少的一部分。大多数家庭和办公室都依赖于Wi-Fi来连接网络和进行各种在线活动。然而&#xff0c;有时我们可能会遇到网络连接不稳定或速度较慢的问题。这可能是由于IP地址的设置不当所导致的。虎观代理小二二将向您介绍如何改变Wi-Fi的IP地址&…

微服务不是问题,无能才是!

微服务不是问题&#xff0c;认知能力才是关键&#xff0c;无法意识到"认知负荷"存在的人&#xff0c;是无能的人&#xff0c;是组织无能 微服务本身并不是问题&#xff0c;对于较小的产品&#xff0c;单体架构也不一定更适合。 无能 软件工程领域的炒作令人难以置信…

内存条选购注意事项(电脑,笔记本)

电脑内存条的作用、选购技巧以及注意事项详解 - 郝光明的个人空间 - OSCHINA - 中文开源技术交流社区 现在的电脑直接和内存条联系 电脑上的所有输入和输出都只能依靠内存条 现在买双条而不是单条 买两个相同的内存条最好 笔记本先分清是低电压还是标准电压&#xff0c;DD…