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

Golang自定义结构体中Unmarshal mapset报错问题咨询

解决mapset.Set无法JSON反序列化的问题

Go标准库的encoding/json包仅能处理内置类型,或实现了json.Marshaler/json.Unmarshaler接口的自定义类型。mapset.Set本身未实现反序列化接口,因此当JSON数组要解析到Set[int]类型字段时,就会抛出json: cannot unmarshal array into Go struct field A.b of type mapset.Set[int]错误。

下面提供两种可行的解决方法:

方案一:自定义包装类型并实现JSON接口

创建一个包装mapset.Set[int]的自定义类型,手动实现序列化和反序列化方法,让JSON包能正确识别处理逻辑。

package main

import (
	"encoding/json"
	"fmt"

	mapset "github.com/deckarep/golang-set/v2"
)

// 自定义包装类型,封装mapset.Set[int]
type IntSet mapset.Set[int]

// 实现MarshalJSON,将Set转为JSON数组
func (s IntSet) MarshalJSON() ([]byte, error) {
	return json.Marshal(s.ToSlice())
}

// 实现UnmarshalJSON,将JSON数组转为Set
func (s *IntSet) UnmarshalJSON(data []byte) error {
	var nums []int
	if err := json.Unmarshal(data, &nums); err != nil {
		return err
	}
	*s = IntSet(mapset.NewSet(nums...))
	return nil
}

// 结构体使用自定义的IntSet类型
type A struct {
	B IntSet `json:"b"`
}

func main() {
	// 序列化测试
	a := A{B: IntSet(mapset.NewSet(1, 2, 3))}
	r, err := json.Marshal(a)
	fmt.Println(string(r), err) // 输出: {"b":[1,2,3]} <nil>

	// 反序列化测试
	var b A
	err = json.Unmarshal(r, &b)
	fmt.Println(b.B, err) // 输出: {1 2 3} <nil>
}

方案二:用切片作为中间转换层

在结构体中添加一个未导出的切片字段作为中间载体,先将JSON数组解析到切片,再手动转换为mapset.Set。

package main

import (
	"encoding/json"
	"fmt"

	mapset "github.com/deckarep/golang-set/v2"
)

type A struct {
	B mapset.Set[int] `json:"b"`
	// 未导出的中间切片,不参与JSON序列化/反序列化
	bSlice []int `json:"-"`
}

// 实现UnmarshalJSON,先解析到切片再转Set
func (a *A) UnmarshalJSON(data []byte) error {
	// 定义临时结构体用于解析JSON
	type tempA struct {
		BSlice []int `json:"b"`
	}
	var t tempA
	if err := json.Unmarshal(data, &t); err != nil {
		return err
	}
	// 将切片转换为Set
	a.B = mapset.NewSet(t.BSlice...)
	return nil
}

// 可选:自定义序列化逻辑,将Set转为切片再序列化
func (a A) MarshalJSON() ([]byte, error) {
	type tempA struct {
		BSlice []int `json:"b"`
	}
	t := tempA{
		BSlice: a.B.ToSlice(),
	}
	return json.Marshal(t)
}

func main() {
	a := A{B: mapset.NewSet(1, 2, 3)}
	r, err := json.Marshal(a)
	fmt.Println(string(r), err) // 输出: {"b":[1,2,3]} <nil>

	var b A
	err = json.Unmarshal(r, &b)
	fmt.Println(b.B, err) // 输出: {1 2 3} <nil>
}

两种方案都能解决问题:方案一更通用,适合需要在多个场景使用Set的JSON序列化需求;方案二更轻量化,适用于单个结构体的特殊处理场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 11:45:34