跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

如何在 Go 中遍历结构体时排除空字段

本文介绍如何使用反射(reflect)动态获取结构体中非空字段的名称,跳过零值(如空字符串、nil 指针、零整数等),适用于表单处理、api 请求过滤等场景。 在 Go 中,结构体字段默认初始化为对应类型的零值(如 string 为 "",int 为 0,指针为 nil)。当需要仅处理用户显式赋值的字段(例如解析 Web 表单或配置输入)时,直接遍历所有字段会包含大量无意义的零值字段。此时,需结合 reflect 包判断每个字段是否“非空”。 核心思路是:对每个字段的 reflect.Value 调用自定义的 empty() 判断函数,仅输出非空字段名。 以下是完整可运行的示例代码:
package main import ( "fmt" "reflect" ) type Users struct { Name string Password string Age int Token *string } // empty 判断 reflect.Value 是否为该类型的零值 func empty(v reflect.Value) bool { switch v.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return v.Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return v.Uint() == 0 case reflect.String: return v.String() == "" case reflect.Ptr, reflect.Slice, reflect.Map, reflect.Interface, reflect.Chan: return v.IsNil() case reflect.Bool: return !v.Bool() case reflect.Float32, reflect.Float64: return v.Float() == 0 case reflect.Struct: // 可选:递归判断结构体是否全为零值(按需扩展) // 此处简化处理:视为非空(因 Struct 本身不可 nil) return false } return false } func main() { token := "abc123" u := Users{ Name: "Robert", Password: "", // 空字符串 → 被排除 Age: 0, // 零值 int → 被排除 Token: &token, // 非 nil 指针 → 保留 } val := reflect.ValueOf(u) typ := reflect.TypeOf(u) fmt.Println("非空字段名:") for i := 0; i < val.NumField(); i++ { field := val.Field(i) if !empty(field) { fmt.Println(typ.Field(i).Name) } } }
输出结果: php版微信js-sdk支付接口类 php版微信js-sdk支付接口类 下载
非空字段名: Name Token
✅ 关键说明: empty() 函数覆盖了常见类型(字符串、数值、布尔、指针、切片、映射等)的零值判断逻辑; 对 struct 类型未做深度判空(因其不可为 nil),若需严格检查嵌套结构体是否全为零值,可递归调用 empty(); 注意:reflect.ValueOf(u) 传入的是值拷贝,因此无法检测指针字段本身的 nil 状态以外的深层内容(如 *string 指向空字符串仍算“非空”,但其解引用值为空——这取决于业务语义); 若结构体含导出字段(首字母大写)且需支持 JSON 标签映射等,可进一步结合 StructField.Tag 提取自定义标识(如 js on:"name,omitempty")。 此方法轻量、通用,适合构建灵活的数据校验、序列化过滤或动态 API 参数提取模块。

相关文章