Go 反射 reflect

Go 语言的 reflect 包是一个非常强大的工具,它允许程序在运行时检查和处理其他对象的结构。使用 reflect,你可以获取类型的信息,调用方法,以及读写结构体字段,即使这些信息在编译时是未知的。

1. 获取类型信息

package main

import (
	"fmt"
	"reflect"
)

func main() {
	x := 42
	fmt.Println("Type:", reflect.TypeOf(x))   // 输出类型
	fmt.Println("Value:", reflect.ValueOf(x)) // 输出值
}

2. 使用 reflect.ValueOf 进行类型断言

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var i interface{} = "hello"

	s, ok := i.(string)
	if !ok {
		fmt.Println("Not a string")
		return
	}
	fmt.Println(s)

	// 使用 reflect.ValueOf 重新解析接口
	v := reflect.ValueOf(i)
	if v.Kind() == reflect.String {
		fmt.Println("String value:", v.String())
	}
}

3. 修改结构体字段 

package main

import (
	"fmt"
	"reflect"
)

type Person struct {
	Name string
	Age  int
}

func main() {
	p := Person{Name: "Alice", Age: 30}
	v := reflect.ValueOf(&p)

	// 修改结构体的字段
	v.Elem().FieldByName("Age").SetInt(35)

	// 输出修改后的值
	fmt.Println(p) // 输出 Age 已经被修改为 35
}

4. 调用方法

案例一
package main

import (
	"fmt"
	"reflect"
)

func add(x, y int) int {
	return x + y
}

func main() {
	v := reflect.ValueOf(add) // 确保 add 是一个可调用的函数
	if v.Kind() == reflect.Func {
		// 准备参数
		args := []reflect.Value{
			reflect.ValueOf(3),
			reflect.ValueOf(4),
		}
		// 调用函数
		results := v.Call(args)
		fmt.Println("Result:", results[0].Int()) // 输出: Result: 7
	}
}
 案例二
package main

import (
	"fmt"
	"reflect"
)

type Calculator struct{}

func (c *Calculator) Add(x, y int) int {
	return x + y
}

func main() {
	calc := Calculator{}
	rc := reflect.ValueOf(&calc)

	// 获取 Add 方法
	addMethod := rc.MethodByName("Add")

	// 调用 Add 方法
	results := addMethod.Call([]reflect.Value{reflect.ValueOf(1), reflect.ValueOf(2)})
	fmt.Println("Result:", results[0].Int()) // 输出 3
}

5. 处理结构体标签

package main

import (
	"fmt"
	"reflect"
)

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	p := Person{Name: "Alice", Age: 30}
	v := reflect.TypeOf(&p) //返回的是指向该结构体的指针类型
	t := v.Elem()           //t 是 Person 结构体的 reflect.Type

	//遍历结构体
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		jsonTag := field.Tag.Get("json")
		fmt.Printf("%s: %s\n", field.Name, jsonTag)
	}
}

汇总

package main

import (
	"fmt"
	"reflect"
)

func main() {
	//1. 获取变量类型
	fmt.Println("获取变量类型")
	fmt.Println(reflect.TypeOf(10))                          //int
	fmt.Println(reflect.TypeOf(10.0))                        //float64
	fmt.Println(reflect.TypeOf(struct{ age int }{10}))       //struct { age int }
	fmt.Println(reflect.TypeOf(map[string]string{"a": "a"})) //map[string]string
	fmt.Println("")
	//2. 获取变量值
	fmt.Println("获取变量值")
	fmt.Println(reflect.ValueOf("hello word"))                //hello word
	fmt.Println(reflect.ValueOf(struct{ age int }{10}))       //{10}
	fmt.Println(reflect.TypeOf(struct{ age int }{10}).Kind()) //struct
	//类型判断
	if t := reflect.TypeOf(struct{ age int }{10}).Kind(); t == reflect.Struct {
		fmt.Println("是结构体")
	} else {
		fmt.Println("不是结构体")
	}
	//修改目标对象
	str := "hello word"
	//普通变量修改
	reflect.ValueOf(&str).Elem().SetString("张三")
	fmt.Println(str)
	//结构体变量修改
	user := User{Name: "张三", Age: 10}
	//Elem() 获取user原始的值
	elem := reflect.ValueOf(&user).Elem()
	//FieldByName() 通过Name返回具有给定名称的结构字段 通过SetString 修改原始的值
	elem.FieldByName("Name").SetString("李四")
	elem.FieldByName("Age").SetInt(18)
	fmt.Println(user)
	
	//获取结构体的标签的值
	fmt.Println(reflect.TypeOf(&user).Elem().Field(0).Tag.Get("name"))
	//调用无参方法
	reflect.ValueOf(&user).MethodByName("Say").Call([]reflect.Value{})
	reflect.ValueOf(user).MethodByName("Say").Call(make([]reflect.Value, 0))
	//调用有参方法
	reflect.ValueOf(user).MethodByName("SayContent").Call([]reflect.Value{reflect.ValueOf("该说话了"), reflect.ValueOf(1)})
	//调用本地的方法
	reflect.ValueOf(Hello).Call([]reflect.Value{})
	reflect.ValueOf(Hello).Call(nil)
	fmt.Printf("%#v\n", reflect.TypeOf(user).Field(0))
}
func Hello() {
	fmt.Println("hello")
}

type Person struct {
	Name string
}
type User struct {
	Person        // //反射会将匿名字段作为一个独立字段来处理
	Name   string `json:"name" name:"张三"`
	Age    int
}

func (_ User) Say() {
	fmt.Println("user 说话")
}
func (_ User) SayContent(content string, a int) {
	fmt.Println("user", content, a)
}

 

注意

  • 使用 reflect 包可能会对性能有一定影响,因为它涉及到运行时的类型检查和反射操作。
  • 反射操作通常用于像 JSON 编码/解码、数据库 ORM 系统、以及其他需要动态处理类型的场景。

reflect 包非常强大,但使用不当也可能导致代码难以理解和维护。因此,建议只在确实需要动态类型处理时使用 reflect

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值