反射的结构体
type Type interface {
Align () int
FieldAlign () int
Method (int) Method
MethodByName (string) (Method, bool)
NumMethod () int
Name () string
PkgPath () string
Size () uintptr
String () string
Kind () Kind
Implements (u Type) bool
AssignableTo (u Type) bool
ConvertibleTo (u Type) bool
Comparable () bool
Bits () int
Elem () Type
Field (i int) StructField
FieldByIndex (index []int) StructField
FieldByName (name string) (StructField, bool)
FieldByNameFunc (match func(string) bool) (StructField, bool)
NumField () int
In (i int) Type
NumIn () int
NumOut () int
Out (i int) Type
IsVariadic () bool
Key () Type
Len () int
ChanDir () ChanDir
common () *rtype
uncommon () *uncommonType
}
反射三定律
反射包里有两个接口类型要先了解一下.
reflect.Type 提供一组接口处理interface 的类型,即(value, type )中的type
reflect.Value提供一组接口处理interface 的值,即(value, type )中的value
下面会提到反射对象,所谓反射对象即反射包里提供的两种类型的对象。
reflect.Type 类型对象
reflect.Value类型对象
反射第一定律:反射可以将interface类型变量转换成反射对象
package main
import (
"fmt"
"reflect"
)
func main () {
var x float64 = 3.4
t := reflect.TypeOf(x)
fmt.Println("type:" , t)
v := reflect.ValueOf(x)
fmt.Println("value:" , v)
}
程序输出如下:
type : float64
value: 3.4
注意:反射是针对interface 类型变量的,其中TypeOf()和ValueOf()接受的参数都是interface {}类型的,也即x值是被转成了interface 传入的。
除了reflect.TypeOf()和reflect.ValueOf(),还有其他很多方法可以操作,本文先不过多介绍,否则一不小心会会引起困惑。
反射第二定律:反射可以将反射对象还原成interface对象
package main
import (
"fmt"
"reflect"
)
func main () {
var x float64 = 3.4
v := reflect.ValueOf(x)
var y float64 = v.Interface().(float64 )
fmt.Println("value:" , y)
}
对象x转换成反射对象v,v又通过Interface()接口转换成interface 对象,interface 对象通过.(float64 )类型断言获取float64 类型的值。
反射第三定律:反射对象可修改,value值必须是可设置的
通过反射可以将interface类型变量转换成反射对象,可以使用该反射对象设置其持有的值。在介绍何谓反射对象可修改前,先看一下失败的例子:
package main
import (
"reflect"
)
func main () {
var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.1 )
}
如下代码,通过反射对象v设置新值,会出现panic。报错如下:
panic: reflect: reflect.Value.SetFloat using unaddressable value
错误原因即是v是不可修改的。
反射对象是否可修改取决于其所存储的值,回想一下函数传参时是传值还是传址就不难理解上例中为何失败了。
上例中,传入reflect.ValueOf()函数的其实是x的值,而非x本身。即通过v修改其值是无法影响x的,也即是无效的修改,所以golang会报错。
想到此处,即可明白,如果构建v时使用x的地址就可实现修改了,但此时v代表的是指针地址,我们要设置的是指针所指向的内容,也即我们想要修改的是*v。 那怎么通过v修改x的值呢?
reflect.Value提供了Elem()方法,可以获得指针向指向的value。看如下代码:
package main
import (
"reflect"
"fmt"
)
func main () {
var x float64 = 3.4
v := reflect.ValueOf(&x)
v.Elem().SetFloat(7.1 )
fmt.Println("x :" , v.Elem().Interface())
}
输出为:
x : 7.1
如何通过反射来进行结构体方法的调用?
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int
Sex string
}
func (p Person) Say(msg string ) {
fmt.Println("hello," ,msg)
}
func (p Person) PrintInfo() {
fmt.Printf("姓名:%s,年龄:%d,性别:%s\n" ,p.Name,p.Age,p.Sex)
}
func (p Person) Test(i,j int ,s string ){
fmt.Println(i,j,s)
}
func main () {
p2 := Person{"张三" ,20 ,"男" }
getValue := reflect.ValueOf(p2)
methodValue1 := getValue.MethodByName("PrintInfo" )
fmt.Printf("Kind : %s, Type : %s\n" ,methodValue1.Kind(),methodValue1.Type())
methodValue1.Call(nil )
args1 := make ([]reflect.Value, 0 )
methodValue1.Call(args1)
methodValue2 := getValue.MethodByName("Say" )
fmt.Printf("Kind : %s, Type : %s\n" ,methodValue2.Kind(),methodValue2.Type())
args2 := []reflect.Value{reflect.ValueOf("反射机制" )}
methodValue2.Call(args2)
methodValue3 := getValue.MethodByName("Test" )
fmt.Printf("Kind : %s, Type : %s\n" ,methodValue3.Kind(),methodValue3.Type())
args3 := []reflect.Value{reflect.ValueOf(5 ), reflect.ValueOf(2 ),reflect.ValueOf("you" )}
methodValue3.Call(args3)
}
Kind : func , Type : func ()
姓名:张三,年龄:20 ,性别:男
姓名:张三,年龄:20 ,性别:男
Kind : func , Type : func (string )
hello, 反射机制
Kind : func , Type : func (int , int , string )
5 2 you
如何通过反射来进行方法的调用?
package main
import (
"fmt"
"reflect"
)
func main () {
f1 := fun1
value := reflect.ValueOf(f1)
fmt.Printf("Kind : %s , Type : %s\n" ,value.Kind(),value.Type())
value2 := reflect.ValueOf(fun2)
fmt.Printf("Kind : %s , Type : %s\n" ,value2.Kind(),value2.Type())
value.Call(nil )
value2.Call([]reflect.Value{reflect.ValueOf("hello" ),reflect.ValueOf(61 )})
}
func fun1 () {
fmt.Println("我是函数fun1(),无参的。" )
}
func fun2 (s string , i int ) {
fmt.Println("我是函数fun2(),有参数:" ,s,i)
}
Kind : func , Type : func ()
Kind : func , Type : func (string , int )
我是函数fun1(),无参的。
我是函数fun2(),有参数: hello 61
反射未导出的字段
package main
import (
"fmt"
"reflect"
)
type Student struct {
name string
Age int
}
func main () {
var TestStudent = Student{name: "jack" ,Age: 12 ,}
fmt.Printf("testStudent.name: %v\n" , getUnExportedField(&TestStudent, "name" ))
}
func getUnExportedField (ptr interface {}, fieldName string ) reflect.Value {
v := reflect.ValueOf(ptr).Elem().FieldByName(fieldName)
return v
}
总结--综合
package main
import (
"fmt"
"reflect"
)
type People struct {
Age int
Name string
}
type TestInterface interface {
GetName() string
}
func (p *People) UpdateName(newName string ) {
p.Name = newName
}
func (p *People) GetName() string {
return p.Name
}
func main () {
u := People{18 , "kuteng" }
fmt.Println(reflect.TypeOf(32 ).Kind())
fmt.Println(reflect.ValueOf(32 ).Kind())
fmt.Println(reflect.TypeOf(&u).MethodByName("UpdateName" ))
fmt.Println(reflect.ValueOf(&u).MethodByName("UpdateName" ))
fmt.Println(reflect.TypeOf(&u).Method(0 ))
fmt.Println(reflect.ValueOf(&u).Method(0 ))
fmt.Println(reflect.TypeOf(&u).NumMethod())
fmt.Println(reflect.ValueOf(&u).NumMethod())
fmt.Println(reflect.TypeOf(u).Field(0 ))
fmt.Println(reflect.ValueOf(u).Field(1 ))
fmt.Println(reflect.TypeOf(u).FieldByIndex([]int {0 }))
fmt.Println(reflect.ValueOf(u).FieldByIndex([]int {0 }))
fmt.Println(reflect.TypeOf(u).FieldByName("ID" ))
fmt.Println(reflect.ValueOf(u).FieldByName("Name" ))
fmt.Println(reflect.TypeOf(u).NumField())
fmt.Println(reflect.ValueOf(u).NumField())
fmt.Println(reflect.TypeOf(u).Align())
fmt.Println(reflect.TypeOf(u).FieldAlign())
fmt.Println(reflect.TypeOf(u).Name())
fmt.Println(reflect.TypeOf(u).PkgPath())
fmt.Println(reflect.TypeOf(u).Size())
fmt.Println(reflect.TypeOf(u).String())
fmt.Println(reflect.TypeOf(u).Implements(reflect.TypeOf((*TestInterface)(nil )).Elem()))
fmt.Println(reflect.TypeOf(u).AssignableTo(reflect.TypeOf(People{})))
fmt.Println(reflect.TypeOf(u).ConvertibleTo(reflect.TypeOf(1 )))
fmt.Println(reflect.TypeOf(u).Comparable())
fmt.Println(reflect.TypeOf(&u).Elem())
fmt.Println(reflect.ValueOf(&u).MethodByName("GetName" ).Call([]reflect.Value{}))
fmt.Println(reflect.ValueOf(&u).CanAddr())
fmt.Println(reflect.ValueOf(&u).CanInterface())
fmt.Println(reflect.ValueOf(&u).CanSet())
a := []int {0 , 1 }
fmt.Println(reflect.ValueOf(a).Cap())
c := make (chan int )
reflect.ValueOf(c).Close()
fmt.Println(reflect.ValueOf(&u).Elem())
fmt.Println(reflect.ValueOf(a).Index(0 ))
reflect.ValueOf(a).Index(0 ).Set(reflect.ValueOf(1 ))
fmt.Println(a[0 ])
fmt.Println(reflect.ValueOf(&u).Interface())
fmt.Println(reflect.ValueOf(&u).IsNil())
fmt.Println(reflect.ValueOf(&u).IsValid())
fmt.Println(reflect.ValueOf(a).Len())
m := map [int ]string {1 : "topgoer.com" , 2 : "topgoer.cn" }
fmt.Println(reflect.ValueOf(m).MapIndex(reflect.ValueOf(1 )))
for index, key := range reflect.ValueOf(m).MapKeys() {
fmt.Println("key=" , key)
fmt.Println("idnex=" , index)
}
fmt.Println(reflect.ValueOf(1 ).Type())
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具