下面是一段反射的代码
package main
import (
"fmt"
"reflect"
)
type Student struct {
Name string `test_tag:"name"`
Age int64 `test_tag:"age1"`
}
func (s Student) Labels() []string {
ss := []string{}
t := reflect.TypeOf(s)
v := reflect.ValueOf(s)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
value := v.Field(i)
tag := field.Tag.Get("test_tag")
zero := reflect.Zero(reflect.TypeOf(value.Interface()))
if tag != "" && !reflect.DeepEqual(value.Interface(), zero.Interface()) {
ss = append(ss, fmt.Sprintf("%s=%v", tag, value))
}
}
return ss
}
func main() {
s := Student{
Age: 0,
Name: "",
}
ss := s.Labels()
fmt.Println(ss)
}
// 上述代码 s:=Studeng{Age:0, Name:""}输出结果为 []
// s := Student{} 输出结果为[]
// 目标状态应为 s:=Student{} 输出 []
// s:=Student{Name:""} 输出 [name=""]
// s:=Student{Age:0} 输出 [age1=0]
// s:=Student{Age:0, Name:""} 输出 [age1=0 name=""]
1、结论
Labels()
函数获取Student
结构体中非空的字段,并返回tag=value
这种形式的数组,但是上诉代码在恰好s
某些字段为对应类型的默认值时无法判断。
2、原因
上诉函数通过reflect.Zero()
的函数获取对应结构体字段的默认值,然后比较reflect.DeepEqual()
判断是否为空,但是这种方法在恰好遇到对应字段为默认值的时候无法进行正确的判断。
3、解决办法
package main
import (
"fmt"
"reflect"
)
type Student struct {
Name *string `test_tag:"name"`
Age *int64 `test_tag:"age1"`
}
func (s Student) Labels() []string {
ss := []string{}
t := reflect.TypeOf(s)
v := reflect.ValueOf(s)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
value := v.Field(i)
tag := field.Tag.Get("test_tag")
zero := reflect.Zero(reflect.TypeOf(value.Interface()))
if tag != "" && !reflect.DeepEqual(value.Interface(), zero.Interface()) {
ss = append(ss, fmt.Sprintf("%s=%v", tag, value.Elem()))
}
}
return ss
}
func main() {
var age int64 = 0
var name string = ""
s := Student{
Age: &age,
Name: &name,
}
ss := s.Labels()
fmt.Println(ss)
}
上述代码中引入 *string *int64
类型,为基础对象引入指针,结构体中存储指针,用指针是否赋值来区别于类型的默认值。上述代码运行结果为 [name= age1=0]
符合预期。