2024-04-06
Go
00
请注意,本文编写于 617 天前,最后修改于 112 天前,其中某些信息可能已经过时。

目录

反射的定义
反射三定律
反射所用到的相关函数
获取变量和方法信息
获取函数信息
判断结构体是否实现某接口
ValueOf常用操作
转为reflect.Type
指针value互转
获取原始类型
空value的判断
修改值
调用方法
其它方法
结构体
切片

程序通过反射可以在运行时访问、检测和修改自身的状态和行为。在Golang中,反射机制可以通过reflect包实现。

反射的定义

反射就是在程序运行时,可以访问自身结构并且做出修改的一种能力。反射机制在 Golang 中是通过 reflect 包来实现的,reflect 包提供了两个主要的类型:reflect.Type 和 reflect.Value。

  • reflect.TypeOf() 获取类型信息,返回 Type 类型
  • reflect.ValueOf() 获取数据信息,返回 Value类型

在go反射系统中,都是通过将 interface{} 转换为 TypeValue类型,然后通过对Type和Value的操作,实现相应的功能。

反射三定律

  1. 反射从接口值(interface{},就是any类型)转变为反射对象
  2. 反射从反射对象转变为接口值
  3. 需要修改反射对象的值,其值必须可以设置(指针类型)
go
func main() { var num float64 = 1.2345 // 第一定律 typeOf := reflect.TypeOf(num) fmt.Println("typeOf:", typeOf) // typeOf: float64 valueOf := reflect.ValueOf(num) fmt.Println("valueOf:", valueOf) // valueOf:1.2345 // 第二定律 anyValue := valueOf.Interface().(float64) fmt.Printf("anyValue: %v, %T\n", anyValue, anyValue) // anyValue: 1.2345, float64 val := reflect.ValueOf(&num) val.Elem().SetFloat(1.23)//// 先根据地址值获取对应的实际值再修改其值 fmt.Println("修改后的值:", num) // 修改后的值: 1.23 }

反射所用到的相关函数

这里以结构体为例

获取变量和方法信息

go
type User struct { Username string `json:"username"` Password string `json:"password"` Email string `json:"email"` Age int `json:"age"` Gender string `json:"gender"` } func main() { var user = User{ Username: "qianxunyimeng", Password: "123456", Email: "qianxunyimeng@gmail.com", Age: 25, Gender: "male", } typeUser := reflect.TypeOf(user) fmt.Println("typeOf: ", typeUser) // typeOf: main.User numFields := typeUser.NumField() for i := 0; i < numFields; i++ { field := typeUser.Field(i) fmt.Printf("%d: name(变量名称) = %s offset(首地址偏移量) = %d "+ "anonymous(是否为匿名变量) = %t type(变量类型) = %s exported(是否可导出) = %t tag = %s\n", i, field.Name, field.Offset, field.Anonymous, field.Type, field.IsExported(), field.Tag, ) } fmt.Println("===========") //使用变量名称获取字段 if field, ok := typeUser.FieldByName("Username"); ok { fmt.Printf("name(变量名称) = %s offset(首地址偏移量) = %d "+ "anonymous(是否为匿名变量) = %t type(变量类型) = %s exported(是否可导出) = %t tag = %s\n", field.Name, field.Offset, field.Anonymous, field.Type, field.IsExported(), field.Tag, ) } fmt.Println("===========") //根据索引获取字段 field := typeUser.FieldByIndex([]int{3}) fmt.Printf("name(变量名称) = %s offset(首地址偏移量) = %d "+ "anonymous(是否为匿名变量) = %t type(变量类型) = %s exported(是否可导出) = %t tag = %s\n", field.Name, field.Offset, field.Anonymous, field.Type, field.IsExported(), field.Tag, ) }

输出如下

typeOf: main.User 0: name(变量名称) = Username offset(首地址偏移量) = 0 anonymous(是否为匿名变量) = false type(变量类型) = string exported(是否可导出) = true tag = json:"username" 1: name(变量名称) = Password offset(首地址偏移量) = 16 anonymous(是否为匿名变量) = false type(变量类型) = string exported(是否可导出) = true tag = json:"password" 2: name(变量名称) = Email offset(首地址偏移量) = 32 anonymous(是否为匿名变量) = false type(变量类型) = string exported(是否可导出) = true tag = json:"email" 3: name(变量名称) = Age offset(首地址偏移量) = 48 anonymous(是否为匿名变量) = false type(变量类型) = int exported(是否可导出) = true tag = json:"age" 4: name(变量名称) = Gender offset(首地址偏移量) = 56 anonymous(是否为匿名变量) = false type(变量类型) = string exported(是否可导出) = true tag = json:"gender" =========== name(变量名称) = Username offset(首地址偏移量) = 0 anonymous(是否为匿名变量) = false type(变量类型) = string exported(是否可导出) = true tag = json:"username" =========== name(变量名称) = Age offset(首地址偏移量) = 48 anonymous(是否为匿名变量) = false type(变量类型) = int exported(是否可导出) = true tag = json:"age"

获取函数信息

go
import ( "crypto/md5" "encoding/hex" "fmt" "reflect" ) type User struct { Username string `json:"username"` Password string `json:"password"` Email string `json:"email"` Age int `json:"age"` Gender string `json:"gender"` } func (u User) GetUsername() string { return u.Username } func (u *User) GetEmail() string { return u.Email } func (u *User) SetPassworld(pass string) string { md5New := md5.New() md5New.Write([]byte(pass)) // hex转字符串 md5String := hex.EncodeToString(md5New.Sum(nil)) fmt.Println(md5String) return md5String } func main() { var user = &User{ Username: "qianxunyimeng", Password: "123456", Email: "qianxunyimeng@gmail.com", Age: 25, Gender: "male", } typeOf := reflect.TypeOf(user.SetPassworld) // 获取函数的参数类型 for i := 0; i < typeOf.NumIn(); i++ { //fmt.Println(typeOf.In(i).String()) fmt.Printf("入参类型:%s\n", typeOf.In(i).Kind()) // 入参类型:string } // 获取函数的返回值类型 for i := 0; i < typeOf.NumOut(); i++ { fmt.Printf("出参类型:%s\n", typeOf.Out(i).Kind()) // 出参类型:string } }

判断结构体是否实现某接口

go
import ( "fmt" "reflect" ) type People interface { Say() string } type User struct { Username string `json:"username"` Email string `json:"email"` Age int `json:"age"` } func (u *User) Say() string { return fmt.Sprintf("Hello, my name is %s", u.Username) } func main() { //首先需要获取到接口到类型 peopleType := reflect.TypeOf((*People)(nil)).Elem() fmt.Println("people是否是一个接口: ", peopleType.Kind() == reflect.Interface) // true // 判断User是否实现了People接口,实现接口有两种形式,指针和非指针 noPointUser := reflect.TypeOf(User{}) pointUser := reflect.TypeOf(&User{}) fmt.Println("noPointUser是否实现了People接口: ", noPointUser.Implements(peopleType)) // false fmt.Println("pointUser是否实现了People接口: ", pointUser.Implements(peopleType)) // true }

ValueOf常用操作

转为reflect.Type

go
type User struct { Username string `json:"username"` Email string `json:"email"` Age int `json:"age"` } func (u *User) Say() string { return fmt.Sprintf("Hello, my name is %s", u.Username) } func main() { user := User{ Username: "John", Email: "john@example.com", Age: 30, } userValueOf := reflect.ValueOf(&user) username := userValueOf.Elem().FieldByName("Username") fmt.Println("Username:", username) // Username: John username.SetString("Tom") fmt.Println("Username:", username) // Username: Tom userTypeOf := userValueOf.Type() fmt.Println("type: ", userTypeOf) // type: *main.User fmt.Println("kind: ", userTypeOf.Kind()) // kind: ptr }

指针value互转

go
type User struct { Username string `json:"username"` Email string `json:"email"` Age int `json:"age"` } func main() { user := User{ Username: "John", Email: "john@example.com", Age: 30, } pointUserValueof := reflect.ValueOf(&user) fmt.Println(pointUserValueof.Type()) // *main.User /** func (v Value) Elem() Value 方法返回v指向的对象。 要求v必须是interface或指针。 */ noPointUserValueof := pointUserValueof.Elem() // 获取指针指向到具体对象 fmt.Println(noPointUserValueof.Type()) // main.User pointUserValueof = noPointUserValueof.Addr() // 转换为指针类型 fmt.Println(pointUserValueof.Type()) // *main.User }

获取原始类型

go
type User struct { Username string `json:"username"` Email string `json:"email"` Age int `json:"age"` } func main() { user := User{ Username: "John", Email: "john@example.com", Age: 30, } pointUserValueof := reflect.ValueOf(&user) noPointUserValueof := pointUserValueof.Elem() // 获取指针指向到具体对象 // 想把reflect.Value转换为User u := noPointUserValueof.Interface().(User) // func (v Value) Interface() (i any) 这里需要把any强制转换为User fmt.Println(u.Username) // John }

空value的判断

go
type User struct { Username string `json:"username"` Email string `json:"email"` Age int `json:"age"` } func main() { // 情形一 var i interface{} // 没有指向具体的值 v := reflect.ValueOf(i) fmt.Println("kind:", v.Kind()) // kind: invalid if !v.IsValid() { fmt.Println("value is invalid") } // 情形二 var user *User = nil v = reflect.ValueOf(user) // value指向一个nil if v.IsValid() { fmt.Printf("v持有的值是nil %t\n", v.IsNil()) // v持有的值是nil true } // 情形三 var u User // 只声明没有初始化,里面的值是零值 v = reflect.ValueOf(u) if v.IsValid() { fmt.Printf("v持有的值是零值 %t\n", v.IsZero()) // v持有的值是零值 true } }

修改值

go
type User struct { Username string `json:"username"` age int `json:"age"` } func main() { var user = User{ Username: "sql", age: 24, } valueOf := reflect.ValueOf(&user) valueOf.Elem().FieldByName("Username").SetString("Tom") fmt.Println(user.Username) // Tom ageValue := valueOf.Elem().FieldByName("age") if ageValue.CanSet() { ageValue.SetInt(18) } else { fmt.Println("私有成员不能修改") // 私有成员不能修改 } }

调用方法

go
type User struct { Username string `json:"username"` age int `json:"age"` } func (u *User) GetName() string { return u.Username } func (u *User) SetName(username string) { u.Username = username } func main() { var user = User{ Username: "Tom", age: 18, } valueOf := reflect.ValueOf(&user) methodByname := valueOf.MethodByName("GetName") // 没有参数就传递空切片 result := methodByname.Call([]reflect.Value{}) for _, v := range result { fmt.Println(v.Interface()) // Tom } methodByname = valueOf.MethodByName("SetName") methodByname.Call([]reflect.Value{reflect.ValueOf("Jerry")}) fmt.Println(user) // {Jerry 18} }

其它方法

结构体

go
// 通过反射的方式创建结构体 // 首先获取结构体对应的Type userType := reflect.TypeOf(User{}) userValue := reflect.New(userType) // 相当于 valueOf(&User{}) 是一个指针类型的值 userValue.Elem().FieldByName("Username").SetString("tom") user := userValue.Elem().Interface().(User) fmt.Println(user) // {tom 0}

切片

type User struct { Username string `json:"username"` Age int `json:"age"` } func (u *User) GetName() string { return u.Username } func (u *User) SetName(username string) { u.Username = username } func main() { // 通过反射的方式创建切片 sliceType := reflect.TypeOf([]User{}) sliceValue := reflect.MakeSlice(sliceType, 1, 3) sliceValue.Index(0).FieldByName("Username").SetString("jerry") sliceValue.Index(0).FieldByName("Age").Set(reflect.ValueOf(20)) fmt.Println(sliceValue) // [{jerry 20}] var newUser = User{ Username: "Tom", Age: 23, } sliceValue = reflect.Append(sliceValue, reflect.ValueOf(newUser)) fmt.Println(sliceValue) // [{jerry 20} {Tom 23}] // 通过反射的方式扩容切片 } func expandSlice(s []interface{}, newCap int) error { v := reflect.ValueOf(s) if v.Kind() != reflect.Slice { return errors.New("expandSlice() interface argument must be a slice") } if newCap <= v.Cap() { return nil } // 创建一个新的切片,容量为新的容量,长度不变 newSlice := reflect.MakeSlice(v.Type(), v.Len(), newCap) reflect.Copy(newSlice, v) //将旧切片拷贝到新切片 ptr := reflect.ValueOf(s).Elem() ptr.Set(newSlice) return nil }
如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:繁星

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!