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