Golang中的反射

本文详细探讨了Go语言中的反射机制,包括reflect.Type类型和值的使用,例如通过reflect.TypeOf获取类型信息,以及如何利用反射操作结构体字段、方法、内存大小等。示例中展示了如何调用对象的方法,如http.Client的Get方法,并分析了结构体的内存布局和大小。此外,还讲解了反射在处理通道、映射和长度信息时的方法。
摘要由CSDN通过智能技术生成

Golang中的反射


前言

Go是一门静态语言,对反射有很好的支持,反射相关的功能在Go标准包reflect下。


提示:以下是本篇文章正文内容,下面案例可供参考

一、reflect.Type类型和值

通过reflect.TypeOf方法可以得到一个reflect.Type类型的变量,方法入参是类型为interface{}。如果参数传递的是一个非接口类型的变量,则返回值标识该类型对应的值;如果传递的是接口类型变量,则返回值reflect.Type会动态指向接口实际的值。reflect.Type是一个接口类型,提供了众多可以获取变量更多信息的方法。其中某些方法只对某些具体类型的变量有效,如果调用不正确则会引发panic,故需要注意相关方法可以作用的变量类型。代码如下:

package main

import (
	"fmt"
	"math"
	"net/http"
	"reflect"
	"unsafe"
)

type User struct {
	Name  string `json:"name" xml:"ch_name"`
	Money int32  `json:"money" xml:"i_money"`
	Age   uint8  `json:"age" xml:"i_age"`
}

func (user *User) SetName(name string) {
	user.Name = name
}

func main() {
	fmt.Println("studyMethodRelatedFunc=>")
	studyMethodRelatedFunc()
	fmt.Println()
	fmt.Println("studyMemRelatedFunc=>")
	studyMemRelatedFunc()
	fmt.Println()
	fmt.Println("studyStructFiledRelatedFunc")
	studyStructFiledRelatedFunc()
	fmt.Println()
	fmt.Println("studyKeyElemLenFunc")
	studyKeyElemLenFunc()
}

// studyKeyElemLenFunc Len,Key,Elem方法研究
func studyKeyElemLenFunc() {
	var ch = make(chan []map[[16]uint8]string)
	// Elem()方法可以作用在Array, Chan, Map, Ptr, and Slice上
	fmt.Println(reflect.TypeOf(ch).Elem().Elem().Elem())
	// Key()只能作用在map上
	fmt.Println(reflect.TypeOf(ch).Elem().Elem().Key())
	// Len只能作用在Array上,Slice不行
	//fmt.Println(reflect.TypeOf(ch).Elem().Len()) //panic: reflect: Len of non-array type []map[[16]uint8]string
	fmt.Println(reflect.TypeOf(ch).Elem().Elem().Key().Len())
}

// studyStructFiledRelatedFunc 结构体成员相关方法研究
func studyStructFiledRelatedFunc() {
	user := User{
		Name:  "zhangsan",
		Age:   20,
		Money: math.MaxInt32,
	}

	for i := 0; i < reflect.TypeOf(user).NumField(); i++ {
		fieldName := reflect.TypeOf(user).Field(i).Name
		fieldType := reflect.TypeOf(user).Field(i).Type
		fieldTag := reflect.TypeOf(user).Field(i).Tag

		fmt.Println(i+1, "字段名:", fieldName,
			",字段类型:", fieldType,
			",字段tag:", fieldTag,
			",json:", fieldTag.Get("json"),
			",xml:", fieldTag.Get("xml"))

	}
}

// studyMemRelatedFunc 内存大小相关方法研究
func studyMemRelatedFunc() {
	user := User{
		Name:  "zhangsan",
		Age:   20,
		Money: math.MaxInt32,
	}

	//如上查看执行结果,结构体User占用的内存大小为24个字节,在64为操作系统上,
	//内存对齐方式为8字节对齐,如果定义结构体如下,猜测内存大小会是多少?
	//答案是:32=8+16+8
	//type User struct {
	//	Money int32
	//	Name  string
	//	Age   uint8
	//}
	sizeOfUserPointer := reflect.TypeOf(&user).Size()
	sizeOfUser := reflect.TypeOf(user).Size()
	fmt.Println("User指针大小:", sizeOfUserPointer)
	fmt.Println("User大小:", sizeOfUser)
	fmt.Println("Name大小:", reflect.TypeOf(user.Name).Size())
	fmt.Println("Age大小:", reflect.TypeOf(user.Age).Size())
	fmt.Println("Money大小:", reflect.TypeOf(user.Money).Size())
}

// sudyMethodRelatedFunc reflect 包中method相关方法研究
func studyMethodRelatedFunc() {
	client := &http.Client{}
	// 获取对象的类型
	tc := reflect.TypeOf(client)
	// 遍历对象的方法
	fmt.Println("方法列表:")
	for i := 0; i < tc.NumMethod(); i++ {
		fmt.Println(i+1, " ", tc.Method(i))
	}

	fmt.Println()

	// 根据名称获取对象的方法
	m, ok := tc.MethodByName("Get")
	if !ok {
		panic("method Get dose not exists")
	}

	// 获取Get方法
	getFunc := m.Func
	// 请求CSDN地址测试
	url := "http://www.csdn.com/"

	// Get方法所需要的参数,第一个参数为接收器*http.Client
	values := make([]reflect.Value, 0)
	values = append(values, reflect.ValueOf(client))
	// Get方法所需要的参数,第二个参数为请求地址类型为string
	values = append(values, reflect.ValueOf(url))
	// 调用Call方法,返回结果
	result := getFunc.Call(values)
	// 返回值一为*http.Response指针对象,kind返回值对应的类型
	fmt.Println("调用Get方法返回值:")
	if result[0].Type() == reflect.TypeOf(&http.Response{}) {
		var resp = (*http.Response)(unsafe.Pointer(result[0].Pointer()))
		fmt.Println("返回值1:", resp, result[0].Kind())
	}

	fmt.Println("返回值2:", result[1], " 类型:", result[1].Kind())
	fmt.Println("返回值2 == nil", " 类型:", result[1].IsNil())
}

返回结果如下:

studyMethodRelatedFunc:
方法列表:
1   {CloseIdleConnections  func(*http.Client) <func(*http.Client) Value> 0}
2   {Do  func(*http.Client, *http.Request) (*http.Response, error) <func(*http.Client, *http.Request) (*http.Response, error) Value> 1}
3   {Get  func(*http.Client, string) (*http.Response, error) <func(*http.Client, string) (*http.Response, error) Value> 2}
4   {Head  func(*http.Client, string) (*http.Response, error) <func(*http.Client, string) (*http.Response, error) Value> 3}
5   {Post  func(*http.Client, string, string, io.Reader) (*http.Response, error) <func(*http.Client, string, string, io.Reader) (*http.Response, error) Value> 4}
6   {PostForm  func(*http.Client, string, url.Values) (*http.Response, error) <func(*http.Client, string, url.Values) (*http.Response, error) Value> 5}

调用Get方法返回值:
返回值1: &{200 OK 200 HTTP/2.0 2 0 map[Content-Length:[0] Content-Type:[application/octet-stream] Date:[Fri, 26 Nov 2021 08:55:10 GMT] Server:[openresty] Strict-Transport-Security:[max-age=31536000]] {0xc000074ba0} 0 [] false false map[] 0xc0001aa000 0xc00011e160} ptr
返回值2: <nil>  类型: interface
返回值2 == nil  类型: true

studyMemRelatedFunc:
User指针大小: 8
User大小: 24
Name大小: 16
Age大小: 1
Money大小: 4

studyStructFiledRelatedFunc:
1 字段名: Name ,字段类型: string ,字段tag: json:"name" xml:"ch_name" ,json: name ,xml: ch_name
2 字段名: Money ,字段类型: int32 ,字段tag: json:"money" xml:"i_money" ,json: money ,xml: i_money
3 字段名: Age ,字段类型: uint8 ,字段tag: json:"age" xml:"i_age" ,json: age ,xml: i_age

studyKeyElemLenFunc
string
[16]uint8
16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

空间法则

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值