package main
import (
"fmt"
"reflect"
)
type User struct {
Id int `json:"id"`
Name string `json:"name"`
addr string `json:"_"`
}
func main(){
u := User{Id:1001, Name:"aaa" , addr:"bbb"}
t := reflect.TypeOf(u)
v := reflect.ValueOf(u)
for i := 0; i < v.NumField(); i++ {
if v.Field(i).CanInterface() { //判断是否为可导出字段
fmt.Printf("%s %s = %v -tag:%s \n",
t.Field(i).Name,
t.Field(i).Type,
v.Field(i).Interface(),
t.Field(i).Tag)
}
}
}
//结果
Id int = 1001 -tag:json:"id"
Name string = aaa -tag:json:"name"
注:当结构体中含有非导出字段时,v.Field(i).Interface()会panic,
所以使用v.Field(i).CanInterface()先判断一下
package main
import (
"reflect"
"fmt"
)
type User struct {
Id int
Name string
Address Address
}
type Address struct {
Add string
Res int
}
func main(){
u := User{Id:1001, Name:"aaa" , Address:Address{Add:"ccccccccc", Res:12}}
t := reflect.TypeOf(u)
v := reflect.ValueOf(u)
for i := 0; i < v.NumField(); i++ {
if v.Field(i).CanInterface() { //判断是否为可导出字段
//判断是否是嵌套结构
if v.Field(i).Type().Kind() == reflect.Struct{
structField := v.Field(i).Type()
for j :=0 ; j< structField.NumField(); j++ {
fmt.Printf("%s %s = %v -tag:%s \n",
structField.Field(j).Name,
structField.Field(j).Type,
v.Field(i).Field(j).Interface(),
structField.Field(j).Tag)
}
continue
}
fmt.Printf("%s %s = %v -tag:%s \n",
t.Field(i).Name,
t.Field(i).Type,
v.Field(i).Interface(),
t.Field(i).Tag)
}
}
}
//结果
Id int = 1001 -tag:
Name string = aaa -tag:
Add string = ccccccccc -tag:
Res int = 12 -tag:
func Field(i int) StructField //使用索引来访问字段,索引从0开始,如果越界将panic
func FieldByName(name string) (StructField,bool) //使用名称来访问字段,如果未找到那么返回false
func FieldByNameFunc(match func(string) bool) (StructField,bool) //访问名称使得match函数返回true的字段,在同一个内嵌层次上,只能有一个字段使得match返回true。如果同一层次上多个字段使得match返回true,那么这些字段都认为是不符合要求的
func FieldByIndex(index []int) StructField //这个方法使得访问结构的内嵌字段成为可能。将访问各个层次的字段的索引排列起来,就形成了一个[]int,参数index不可越界,否则panic
package main
import (
"reflect"
"fmt"
)
type Test struct {
Name string
User User
}
type User struct {
Age int
Name string
}
var test Test = Test{
Name:"aaa",
User:User{
Name:"bbb",
Age:12,
},
}
func main() {
sysConfig := reflect.ValueOf(&test).Elem()
fmt.Println(sysConfig.FieldByIndex([]int{1})) //打印User层属性
//fmt.Println(sysConfig.FieldByName("Age")) //直接打印下一层不成功
flag := sysConfig.FieldByName("Age") == reflect.Value{}
if flag {
fmt.Println(sysConfig.FieldByIndex([]int{1}).FieldByName("Age")) //12
}
}
当再加一层, FieldByIndex([]int{1, 2}), 1和2都要加上才可以,直接就写2不行。第0层要使用其他的field方法。
package main
import (
"reflect"
"fmt"
)
type Test struct {
Name string
User User
}
type User struct {
Age int
Name string
Addr Addr
}
type Addr struct {
Address string
}
var test Test = Test{
Name:"aaa",
User:User{
Name:"bbb",
Age:12,
Addr:Addr{
Address:"dddddd",
},
},
}
func main() {
var val reflect.Value
sysConfig := reflect.ValueOf(&test).Elem()
fmt.Println(sysConfig.FieldByIndex([]int{1, 2})) //Addr
//fmt.Println(sysConfig.FieldByName("Age"))
flag := sysConfig.FieldByName("Address") == val
if flag {
fmt.Println(sysConfig.FieldByIndex([]int{1, 2}).FieldByName("Address")) //ddddd
}
}
1.反射只能反射单层结构,如果struct又包含了一个struct那么,需要先遍历前面这个,获取后面struct的指针活元素才能遍历。
type Test struct {
Name string
Test2 Test2
}
type Test2 struct {
Add string
}
//遍历Test 获得Test2指针或者元素才能遍历Test2
func (m *M) Pri()
加不加 *
的问题.
const (
Invalid Kind = iota
Bool
Int
Int8
Int16
Int32
Int64
Uint
Uint8
Uint16
Uint32
Uint64
Uintptr
Float32
Float64
Complex64
Complex128
Array
Chan
Func
Interface
Map
Ptr
Slice
String
Struct
UnsafePointer
)
//底层都是 Kind(f & (1 << 5 -1))所以结果相同, 因为2进制31为 00011111 验证 27 个种类的位数正好是这么多.
** 但是不是很清楚28的情况怎么处理不越界 **, 懂了后补充.
// TypeOf
func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) }
kindMask = (1 << 5) - 1
// ValueOf
const (
flagKindWidth = 5 // there are 27 kinds
flagKindMask flag = 1<<flagKindWidth - 1
)
func (f flag) kind() Kind {
return Kind(f & flagKindMask)
}
获取方法数量,当传入的不是指针的时候, 只能获得struct方法,而不能获得指针方法.
package main
import (
"fmt"
"reflect"
)
type MyStruct struct{
name string
}
func (this *MyStruct)GetName() string {
return this.name
}
func (this MyStruct) Pri() {
fmt.Println(this)
}
func main() {
s := MyStruct{name:"cc"}
t := reflect.TypeOf(s)
v := reflect.ValueOf(s)
//当传入的是struct
fmt.Println(t.NumMethod()) // 1
fmt.Println(v.NumMethod()) // 1
s1 := &MyStruct{name:"cc"} //这里等同于 new(MyStruct), 传入指针
t1 := reflect.TypeOf(s1) //如果是 s 那么这里要传 &s
v1 := reflect.ValueOf(s1)
//传入的是指针, 所以指针方法和struct方法类似
fmt.Println(t1.NumMethod()) // 2
fmt.Println(v1.NumMethod()) // 2
//typeOf 提供了将struct变成指针的方法
t = reflect.PtrTo(t) //将t变为指向t的指针
fmt.Println(t.NumMethod()) // 2
fmt.Println(v.NumMethod()) // 1
//这种是将指针变成struct的方法
if t.Kind() == reflect.Ptr {
t = t.Elem() //将t变成指向的对象
fmt.Println("-----------")
}
fmt.Println(t.NumMethod()) // 1
fmt.Println(v.NumMethod()) // 1
//value 有将指针变成 struct的方法, 没有struct变成指针的方法
if v1.Kind() == reflect.Ptr {
v1 = v1.Elem() //将t变成指向的对象
fmt.Println("-----------")
}
//t1 依然是指针, 但是v1已经变成struct了
fmt.Println(t1.NumMethod()) // 2
fmt.Println(v1.NumMethod()) // 1
}