Golang:解析mapset

huangapple go评论70阅读模式
英文:

Golang: Unmarshal mapset

问题

我正在尝试将mapset解组到用户定义的结构体中,但是我一直收到以下错误信息:

json: 无法将数组解组到类型为 mapset.Set[int] 的 Go 结构体字段 A.b 中 {<nil>}

示例代码:

package main

import (
    "encoding/json"
    "fmt"

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

type A struct {
    B mapset.Set[int] `json:"b"`
}

func main() {
    a := A{mapset.NewSet(1, 2, 3)}
    r, err := json.Marshal(a)
    fmt.Println(r, err)

    var b A
    err = json.Unmarshal(r, &b)
    fmt.Println(b, err)
}

我尝试解组的不是结构体类型,而是 mapset 本身,但结果仍然相同。

我是否做错了什么,还是这是某个内部包的问题?

英文:

I'm trying to Unmarshal mapset in user-defined struct, but I keep getting this error:

json: cannot unmarshal array into Go struct field A.b of type mapset.Set[int] {&lt;nil&gt;}

Sample code:

package main

import (
	&quot;encoding/json&quot;
	&quot;fmt&quot;

	mapset &quot;github.com/deckarep/golang-set/v2&quot;
)

type A struct {
	B mapset.Set[int] `json:&quot;b&quot;`
}

func main() {
	a := A{mapset.NewSet(1, 2, 3)}
	r, err := json.Marshal(a)
	fmt.Println(r, err)

	var b A
	err = json.Unmarshal(r, &amp;b)
	fmt.Println(b, err)
}

I tried to unmarshal not a type struct, but mapset itself, but the result is the same one.

Am I doing something wrong or it is some iternal package issue?

答案1

得分: 3

你可以将mapset.Set[int]类型封装到一个自定义的结构类型中,并为其编写一个json.Unmarshaler的实现。我从未使用过这个库,但是下面是一个示例,展示了如何实现这一点,可能不是最优雅的解决方案,但似乎可以正常工作(这是你问题中代码的修改版本)。比较可以使用reflect.DeepEqual()或集合的Equal()方法进行。

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"reflect"

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

type IntSet struct {
	Values mapset.Set `json:"values"`
}

func (s *IntSet) UnmarshalJSON(data []byte) error {
	// 用于解组目的的匿名结构体。
	v := struct {
		Values []int `json:"values"`
	}{}

	// 将字节解组为包含整数切片的自定义结构体。
	if err := json.Unmarshal(data, &v); err != nil {
		return err
	}

	// 如果结构体中没有集合,则创建一个只包含一个'0'值的新集合。
	if s.Values == nil {
		s.Values = mapset.NewSet(0)
	}

	// 清空集合。
	s.Values.Clear()

	// 将解组的字节中的所有值添加到结构体集合中。
	for _, value := range v.Values {
		s.Values.Add(value)
	}

	return nil
}

func main() {
	a := IntSet{Values: mapset.NewSet(1, 2, 3)}
	r, err := json.Marshal(a)
	fmt.Println(r, err)

	var b IntSet
	err = json.Unmarshal(r, &b)
	fmt.Println(b, err)

	// 使用[reflect.DeepEqual]比较a和b。
	if !reflect.DeepEqual(a, b) {
		log.Fatalln("a和b不相等")
	}

	// 使用任何一个集合的Equal()方法比较a和v的值。
	if !a.Values.Equal(b.Values) || !b.Values.Equal(a.Values) {
		log.Fatalln("a和b的值不相等")
	}
}

另外,如果你打算在最终的代码中进行集合比较,请注意使用两个集合的Equal()方法要比使用reflect.DeepEqual()快得多。上面代码块中的第一个比较示例仅用于测试目的,在生产代码中通常应避免使用反射。

英文:

You can wrap this mapset.Set[int] type into a custom struct type and write a json.Unmarshaler implementation for it. I've never used this library, but here is an example of how can you do that, probably not the most elegant solution but it seems to work fine (it's a modified version of the code in your question). Comparison also works using either reflect.DeepEqual() or a set's Equal() method.

package main
import (
&quot;encoding/json&quot;
&quot;fmt&quot;
&quot;log&quot;
&quot;reflect&quot;
mapset &quot;github.com/deckarep/golang-set/v2&quot;
)
type IntSet struct {
Values mapset.Set[int] `json:&quot;values&quot;`
}
func (s *IntSet) UnmarshalJSON(data []byte) error {
// Anonymous struct for the unmarshalling purposes.
v := struct {
Values []int `json:&quot;values&quot;`
}{}
// Unmarshal bytes into a custom struct that
// contains int slice as the only value.
if err := json.Unmarshal(data, &amp;v); err != nil {
return err
}
// If there is no set inside a struct, create
// a new set with a single &#39;0&#39; value.
if s.Values == nil {
s.Values = mapset.NewSet(0)
}
// Empty the set.
s.Values.Clear()
// Add all the values from the unmarshalled
// bytes to the struct set.
for _, value := range v.Values {
s.Values.Add(value)
}
return nil
}
func main() {
a := IntSet{Values: mapset.NewSet(1, 2, 3)}
r, err := json.Marshal(a)
fmt.Println(r, err)
var b IntSet
err = json.Unmarshal(r, &amp;b)
fmt.Println(b, err)
// Compare a and b using [reflect.DeepEqual].
if !reflect.DeepEqual(a, b) {
log.Fatalln(&quot;a and b are not equal&quot;)
}
// Compare a and v values by using any
// of the sets&#39; Equal() method.
if !a.Values.Equal(b.Values) || !b.Values.Equal(a.Values) {
log.Fatalln(&quot;a and b values are not equal&quot;)
}
}

Also if you intend to put the sets comparison in your final code, please note that using Equal() method on the two sets is much faster than using reflect.DeepEqual(). The first comparison example in the code block above is just for the testing purposes, you should generally avoid using reflection in a production code.

huangapple
  • 本文由 发表于 2022年8月14日 21:18:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/73351968.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定