You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言中JSON蛇形键转驼峰键的高效实现方法问询

高效解决Go结构体JSON蛇形键转驼峰键的方案

你现在手动维护两套结构体的做法确实太繁琐了,尤其是结构体字段多或者需要扩展的时候,很容易出错。下面给你几个更优雅的解决方案:

方案一:利用反射自动转换字段与键名

我们可以写一个通用的工具函数,通过反射遍历结构体的字段,读取原有蛇形JSON标签的值,将其转换为驼峰格式后,构建一个新的map[string]interface{},最后序列化这个map得到驼峰键的JSON。

示例代码:

import (
    "encoding/json"
    "reflect"
    "strings"

    "github.com/iancoleman/strcase" // 用这个库快速实现蛇形转驼峰(不想依赖的话可以自己实现字符串转换)
)

// SnakeToCamelJSON 将带蛇形JSON标签的结构体序列化为驼峰键的JSON
func SnakeToCamelJSON(v interface{}) ([]byte, error) {
    val := reflect.ValueOf(v)
    if val.Kind() == reflect.Ptr {
        val = val.Elem()
    }
    if val.Kind() != reflect.Struct {
        return json.Marshal(v) // 非结构体直接返回原序列化结果
    }

    camelMap := make(map[string]interface{})
    typ := val.Type()

    for i := 0; i < typ.NumField(); i++ {
        field := typ.Field(i)
        jsonTag := field.Tag.Get("json")
        if jsonTag == "" || jsonTag == "-" {
            continue // 忽略无JSON标签或标记为忽略的字段
        }
        // 剥离JSON标签里的额外选项(比如omitempty)
        snakeKey := strings.Split(jsonTag, ",")[0]
        camelKey := strcase.ToLowerCamel(snakeKey) // 转成小驼峰格式

        fieldVal := val.Field(i).Interface()
        // 递归处理嵌套的结构体
        if reflect.ValueOf(fieldVal).Kind() == reflect.Struct {
            nestedJSON, err := SnakeToCamelJSON(fieldVal)
            if err != nil {
                return nil, err
            }
            var nestedMap map[string]interface{}
            if err := json.Unmarshal(nestedJSON, &nestedMap); err != nil {
                return nil, err
            }
            camelMap[camelKey] = nestedMap
        } else {
            camelMap[camelKey] = fieldVal
        }
    }

    return json.Marshal(camelMap)
}

使用时直接传入你的原有结构体就行:

var userWithAddress UserWithAddress
// 假设已经完成了userWithAddress的数据填充
camelJSON, err := SnakeToCamelJSON(userWithAddress)
if err != nil {
    // 处理错误逻辑
}
// camelJSON就是你想要的驼峰键JSON数据

如果不想依赖第三方库,自己实现蛇形转驼峰的函数也很简单:

func snakeToCamel(s string) string {
    parts := strings.Split(s, "_")
    for i := 1; i < len(parts); i++ {
        parts[i] = strings.Title(parts[i])
    }
    return strings.Join(parts, "")
}

方案二:自定义结构体的MarshalJSON方法

如果你的结构体相对固定,也可以给结构体实现json.Marshaler接口,手动控制序列化时的键名转换。这种方式性能比反射更好,但需要为每个结构体编写对应的方法。

示例代码:

func (u BaseUser) MarshalJSON() ([]byte, error) {
    return json.Marshal(map[string]interface{}{
        "userId":   u.ID,
        "userName": u.Name,
        "userEmail": u.Email,
    })
}

func (u UserWithAddress) MarshalJSON() ([]byte, error) {
    baseJSON, err := u.BaseUser.MarshalJSON()
    if err != nil {
        return nil, err
    }
    var baseMap map[string]interface{}
    if err := json.Unmarshal(baseJSON, &baseMap); err != nil {
        return nil, err
    }
    // 添加子结构体的字段
    baseMap["userPostal"] = u.Postal
    baseMap["userCity"] = u.City
    baseMap["userStreet"] = u.Street
    return json.Marshal(baseMap)
}

使用时直接序列化原有结构体即可:

jsonData, err := json.Marshal(userWithAddress)
// jsonData就是驼峰键的JSON结果

这种方式的缺点是结构体扩展时需要同步修改MarshalJSON方法,但比维护两套结构体要轻松不少。

方案三:使用支持自定义命名策略的JSON库(Go 1.18+)

如果你用的是Go 1.18及以上版本,可以换用支持自定义命名策略的第三方JSON库,比如goccy/go-json,它能直接在编解码时自动转换蛇形和驼峰键,完全不用修改原有结构体。

示例代码:

import (
    "os"
    "github.com/goccy/go-json"
)

// 你的原有结构体保持不变
type BaseUser struct {
    ID    int64  `json:"user_id"`
    Name  string `json:"user_name"`
    Email string `json:"user_email"`
}

type UserWithAddress struct {
    BaseUser
    Postal string `json:"user_postal"`
    City   string `json:"user_city"`
    Street string `json:"user_street"`
}

func main() {
    user := UserWithAddress{
        BaseUser: BaseUser{ID: 123, Name: "test", Email: "test@mail.com"},
        Postal: "12312", City: "city", Street: "street",
    }
    // 创建编码器并设置命名策略为小驼峰
    encoder := json.NewEncoder(os.Stdout)
    encoder.SetNamingStrategy(json.LowerCamelCase)
    _ = encoder.Encode(user)
    // 输出结果就是驼峰键的JSON
}

这种方式最简洁,零额外代码维护,只需要替换标准库的JSON编解码工具即可。


内容的提问来源于stack exchange,提问作者Tarasovych

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 08:07:37