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

Go自定义Scan方法反序列化int64底层枚举类型时值恒为0

问题根源

反序列化结果恒为0和你实现的Scan、类型转换逻辑没有关系,核心问题有两个:

  • encoding/json 标准库仅能读写结构体中首字母大写的导出字段,你定义的Person结构体里name、gender均为小写开头的未导出字段,json包做反射解析时没有权限访问这两个字段,因此反序列化过程中根本不会给这两个字段赋值,最终保留类型零值:name为空字符串,底层类型为int64的gender零值就是0(对应Undefined枚举值)。
  • 你实现的Scan()方法是database/sql包定义的sql.Scanner接口,该接口仅在从数据库读取列值时触发,json.Unmarshal执行过程中不会调用这个方法。
修复方案
  1. 首先将Person结构体的字段改为首字母大写的导出格式,保留对应的json tag即可:
type Person struct {
    Name   string `json:"name"`
    Gender Gender `json:"gender"`
}

由于Gender的底层类型是int64,属于json包原生支持的数字类型,改完字段导出权限后,不需要额外实现json反序列化方法,就可以正确把json里的数字值解析为对应Gender枚举值,完全不需要依赖字符串表示。

  1. (可选)如果需要在json反序列化时做值范围校验,可以给*Gender实现json.Unmarshaler接口,示例:
func (g *Gender) UnmarshalJSON(data []byte) error {
    var i int64
    if err := json.Unmarshal(data, &i); err != nil {
        return err
    }
    if i < 0 || i > 3 {
        return fmt.Errorf("invalid gender value: %d", i)
    }
    *g = Gender(i)
    return nil
}

你之前写的Scan、Value方法是给数据库读写场景用的,可以正常保留,不会影响json序列化/反序列化逻辑。

修复后验证代码
package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name   string `json:"name"`
	Gender Gender `json:"gender"`
}

type Gender int64

const (
	Undefined Gender = iota
	Male
	Female
	NonBinary
)

func (g Gender) String() string {
	return [...]string{"Undefined", "Male", "Female", "Non-binary"}[g]
}

func main() {
	var person Person
	jsonPerson := `{"name": "John", "gender": 2}`

	err := json.Unmarshal([]byte(jsonPerson), &person)
	if err != nil {
		panic(err)
	}
    // 输出:{Name:John Gender:Female}
	fmt.Printf("%+v", person)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 04:06:07