【Go】利用 reflect 实现结构体设置默认值

【Go】利用 reflect 实现结构体设置默认值 写 API 时经常会需要结构体中某个参数拥有默认值。但如 Gin 只有 ShouldBindQuery 这种 form 类型支持设置默认值,常用的 ShouldBindJSON 这种 json 类型却不支持,很奇怪。 Gin 中 bind 结构体设置默认值 package main import ( "fmt" "github.com/gin-gonic/gin" ) type FormData struct { Name string `form:"name,default=vksir"` Age int `form:"age,default=18"` } type JsonData struct { Name string `json:"name,default=vksir"` Age int `json:"age,default=18"` } func main() { e := gin.Default() e.GET("/", func(c *gin.Context) { var fd FormData c.ShouldBindQuery(&fd) var jd JsonData c.ShouldBindJSON(&jd) fmt.Printf("FormData: %+v\n", fd) fmt.Printf("JsonData:%+v\n", jd) }) e.Run() } 请求会打印如下结果: FormData: {Name:vksir Age:18} JsonData:{Name: Age:0} 也就是说 JsonData 的默认值没有生效,如果看源码也可以发现 ShouldBindJSON 是没有设置默认值的动作的。 简单实现结构体设置默认值 编辑 structutil/struct.go: package structutil import ( "reflect" "strconv" ) func SetDefault(v any) error { typeOf := reflect.TypeOf(v).Elem() valueOf := reflect.ValueOf(v).Elem() return subSetDefault(typeOf, valueOf) } func subSetDefault(typeOf reflect.Type, valueOf reflect.Value) error { for i := 0; i < typeOf.NumField(); i++ { tField := typeOf.Field(i) vField := valueOf.Field(i) switch tField.Type.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: defaultVal, ok := tField.Tag.Lookup("default") if !ok { continue } defaultValInt, err := strconv.ParseInt(defaultVal, 10, 64) if err != nil { return err } vField.SetInt(defaultValInt) case reflect.String: defaultVal, ok := tField.Tag.Lookup("default") if !ok { continue } vField.SetString(defaultVal) case reflect.Struct: err := subSetDefault(tField.Type, vField) if err != nil { return err } } } return nil } 简单使用: ...

六月 4, 2022  |  263 字  |  总阅读