0

0

如何在 Go 中正确自定义 JSON 编码输出

碧海醫心

碧海醫心

发布时间:2026-02-09 13:42:35

|

427人浏览过

|

来源于php中文网

原创

如何在 Go 中正确自定义 JSON 编码输出

本文详解 go 中通过 `marshaljson()` 方法自定义结构体 json 序列化的方式,指出常见错误(如手动拼接导致无效 json),并提供安全、标准的实现方案,同时对比推荐使用结构体标签的简洁做法。

在 Go 中,当需要精细控制结构体的 JSON 输出格式时,可实现 json.Marshaler 接口(即定义 MarshalJSON() ([]byte, error) 方法)。但直接字符串拼接极易生成非法 JSON——如原代码中仅写入 "foo""true",缺失字段名、引号不匹配、布尔值被错误加引号等,导致解析器报错 invalid character 'o' in literal false。

✅ 正确实现 MarshalJSON():手动生成合规 JSON

必须严格遵循 JSON 语法:对象用 {} 包裹,字段名和字符串值需双引号包裹,布尔值(true/false)不可加引号,字段间用逗号分隔。以下是修正后的完整示例:

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "log"
)

type Info struct {
    name string // 注意:小写字段默认不导出,无法被 json 包访问
    flag bool
}

// MarshalJSON 实现:生成标准 JSON 对象
func (i Info) MarshalJSON() ([]byte, error) {
    var b bytes.Buffer
    b.Write([]byte(`{"name":"`)) // 字段名 + 开始引号
    b.WriteString(i.name)         // 安全写入字符串(自动转义)
    b.Write([]byte(`","flag":`)) // 字段分隔 + 布尔字段名
    if i.flag {
        b.Write([]byte("true")) // 布尔字面量,不加引号
    } else {
        b.Write([]byte("false"))
    }
    b.Write([]byte(`}`)) // 结束大括号
    return b.Bytes(), nil
}

func main() {
    a := []Info{
        {"foo", true},
        {"bar", false},
    }
    out, err := json.Marshal(a)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(string(out))
    // 输出: [{"name":"foo","flag":true},{"name":"bar","flag":false}]
}
⚠️ 关键注意事项:使用 b.WriteString() 替代 b.Write([]byte(...)) 可避免手动处理字符串转义(如 name 含 " 或 \n 时);小写字段(如 name)在结构体中为非导出字段,json 包默认忽略;若坚持用小写字段,需在 MarshalJSON 中显式处理其值(如本例所示);布尔值 true/false 必须以 JSON 原生字面量形式输出,加引号会使其变为字符串,破坏类型一致性(反序列化时无法还原为 bool)。

? 更推荐:使用导出字段 + JSON 标签(零成本定制)

绝大多数场景下,无需手动实现 MarshalJSON。只需将字段首字母大写(使其可导出),再配合 json struct tag 即可灵活控制键名与行为:

type Info struct {
    Name string `json:"name"`   // JSON 键名为 "name"
    Flag bool   `json:"flag"`   // JSON 键名为 "flag"
    // 可选:omitempty 忽略零值字段
    // Age  int    `json:"age,omitempty"`
}

此时调用 json.Marshal() 会自动处理字段映射、转义、类型序列化,且完全兼容 json.Unmarshal()。示例输出与手动实现一致:

视野自助系统小型企业版2.0 Build 20050310
视野自助系统小型企业版2.0 Build 20050310

自定义设置的程度更高可以满足大部分中小型企业的建站需求,同时修正了上一版中发现的BUG,优化了核心的代码占用的服务器资源更少,执行速度比上一版更快 主要的特色功能如下: 1)特色的菜单设置功能,菜单设置分为顶部菜单和底部菜单,每一项都可以进行更名、选择是否隐 藏,排序等。 2)增加企业基本信息设置功能,输入的企业信息可以在网页底部的醒目位置看到。 3)增加了在线编辑功能,输入产品信息,企业介绍等栏

下载
[{"name":"foo","flag":true},{"name":"bar","flag":false}]

此外,json tag 还支持更多高级选项:

  • ,omitempty:当字段为零值(空字符串、0、nil 等)时跳过该字段;
  • -,string:将数值字段序列化为字符串(如 Age intjson:"age,string"→"age":"25"`);
  • -:完全忽略该字段。

✅ 总结:何时选择哪种方式?

方式 适用场景 维护性 安全性
导出字段 + struct tag 字段名映射、零值忽略、数值字符串化等常规定制 高(声明式,无逻辑) 最高(由标准库保障)
自定义 MarshalJSON 需动态计算字段值、嵌套结构重排、加密/脱敏、兼容旧协议等复杂逻辑 中低(需手动维护 JSON 语法) 依赖开发者严谨性

? 最佳实践建议:优先使用 json struct tag;仅当业务逻辑无法通过标签表达时,再谨慎实现 MarshalJSON,并务必通过 json.Valid() 或单元测试验证输出合法性。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

185

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

233

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

345

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

211

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

400

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

302

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

196

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

722

2025.06.17

Golang处理数据库错误教程合集
Golang处理数据库错误教程合集

本专题整合了Golang数据库错误处理方法、技巧、管理策略相关内容,阅读专题下面的文章了解更多详细内容。

127

2026.02.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 9万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 3.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号