
当 JSON 中的 article_type 是字符串(如 "news"),而 Go 结构体中对应字段是自定义结构体 ArticleType 时,json.Unmarshal 会因类型不兼容报错;可通过实现 json.Unmarshaler 接口,让结构体支持从字符串直接解析。
当 json 中的 `article_type` 是字符串(如 `"news"`),而 go 结构体中对应字段是自定义结构体 `articletype` 时,`json.unmarshal` 会因类型不兼容报错;可通过实现 `json.unmarshaler` 接口,让结构体支持从字符串直接解析。
在 Go 的 JSON 反序列化过程中,若目标字段类型为自定义结构体(如 ArticleType),但源 JSON 提供的是简单字符串(如 "news"),标准 json.Unmarshal 无法自动将字符串映射到结构体字段,从而触发典型错误:json: cannot unmarshal string into Go struct field Article.article_type of type models.ArticleType
根本原因在于:Go 的 encoding/json 包默认仅支持「同构映射」——即 JSON 对象 → 结构体、JSON 字符串 → string、JSON 数字 → int/float 等。而此处期望的是「异构映射」:JSON 字符串 → 结构体(且仅填充其 Title 字段)。
✅ 正确解法:为 ArticleType 实现 json.Unmarshaler 接口:
func (a *ArticleType) UnmarshalJSON(data []byte) error {
// 去除首尾引号(json.Unmarshal 传入的字符串字面量带双引号)
s := strings.Trim(string(data), `"`)
a.Title = s
return nil
}
⚠️ 注意事项:
使用约定式提交(Conventional Commits)生成标准化的 Git 提交信息。适用于以下场景: (1) 暂存更改时需要提交信息; (2) 审查 diff 时希望获得结构化摘要; (3) 编写 PR 描述或变更日志(changelog)条目; (4) 用户明确要求“为本次更改编写提交信息”。 该功能会分析已暂存/未暂存的 diff,并生成按类型(type)划分范围的提交信息。
- 必须使用指针接收者(
*ArticleType),否则接口实现无效; - 需手动处理 JSON 字符串的引号包裹(
"news"→news),推荐用strings.Trim(s, "\""); - 若后续需双向序列化(即
json.Marshal时也输出字符串),应同时实现json.Marshaler; - 此方案适用于「单字段轻量映射」场景;若
ArticleType在业务中还需关联 ID 或数据库查询,建议分离「传输层 DTO」与「领域模型」,避免语义混淆。
完整可运行示例(含修复后代码):
package main
import (
"encoding/json"
"fmt"
"strings"
)
type ArticleType struct {
ID uint `json:"id"`
Title string `json:"title"`
}
func (a *ArticleType) UnmarshalJSON(data []byte) error {
s := strings.Trim(string(data), `"`)
a.Title = s
return nil
}
type Article struct {
CreatedAt int `json:"created_at"`
UpdatedAt int `json:"updated_at"`
ArticleType ArticleType `json:"article_type"`
}
func main() {
data := []byte(`[{"created_at":1486579331,"updated_at":1486579331,"article_type":"news"}]`)
var articles []Article
if err := json.Unmarshal(data, &articles); err != nil {
panic(err)
}
fmt.Printf("%+v\n", articles[0].ArticleType) // 输出:{ID:0 Title:"news"}
}
总结:该问题本质是 JSON 类型与 Go 类型契约不一致。通过定制 UnmarshalJSON 方法,我们赋予结构体灵活的反序列化能力,既保持了 API 兼容性(输入仍是简洁字符串),又满足了领域模型的结构需求。这是 Go 中处理「语义简写 JSON」的惯用且高效模式。










