在Go语言中处理集合(Set)的方法和测试方式
首先
Go语言中没有默认提供集合(Set)。
实现方式
1. 切片 (qiē
strSet1 := []string{"element1", "element2", "element3"}
简单的方法。
允许重复,只是一个切片。
对于简单的情况,这就足够了。
2. 映射[接口{}]键结构{}
strSet2 := map[string]struct{}{
"element1": struct{}{},
"element2": struct{}{},
"element3": struct{}{},
}
mapを利用する方法。
struct{}はメモリを圧迫することはない。
3. github.com/deckarep/golang-set/mapset 的网址
strSet3 := mapset.NewSet()
requiredClasses.Add("element1")
requiredClasses.Add("element2")
requiredClasses.Add("element3")
使用包的方法。
有许多方便的方法来操作Set。
内部实现使用了map[interface{}]struct{}。
在https://github.com/deckarep/golang-set上有源代码。
用途的定义是指某物品或事物的目标、目的或功能。
在进行个人开发时,需要对Redis的SMembers功能进行测试。
Redis可以使用Set来存储数据,并且可以使用SMembers来获取数据。
由于go语言中没有Set类型,go-redis的SMembers返回的是[]string。
当需要比较集合时,使用[]string会导致元素之间的顺序无法保证,从而导致测试失败,因此需要使用Set类型。
我认为使用第3种方法的github.com/deckarep/golang-set/mapset过于夸张,所以选择了第2种方法,即使用map[interface{}]struct{}。
如果要将[]string作为集合进行比较,那么为了确保每个元素都包含在内,可能需要进行大量的for循环。
package sample
import (
"testing"
"github.com/go-redis/redis/v7"
)
type RepositoryImpl struct {
Client *redis.Client
}
func New(addr string) (*redis.Client, error) {
client := redis.NewClient(&redis.Options{
Addr: addr,
})
if err := client.Ping().Err(); err != nil {
return nil, errors.Wrapf(err, "failed to ping redis server")
}
return client, nil
}
func (r RepositoryImpl) GetStringSet(key string) ([]string, error) {
result, err := r.Client.SMembers(key).Result()
if err != nil {
return nil, err
}
return result, nil
}
package sample
import (
"testing"
"github.com/go-redis/redis/v7"
)
func NewMockRedis(t *testing.T) *redis.Client {
t.Helper()
s, err := miniredis.Run()
if err != nil {
t.Fatalf("unexpected error while createing test redis server '%#v'", err)
}
client := redis.NewClient(&redis.Options{
Addr: s.Addr(),
})
return client
}
func TestGetStringSet(t *testing.T) {
client := NewMockRedis(t)
r := RepositoryImpl{
Client: client,
}
client.SAdd("testKey", "hoge", "fuga", "piyo")
actual, err := r.GetStringSet("testKey")
if err != nil {
t.Fatalf("unexpected error while GetStringSet '%#v'", err)
}
expected, err := []string{"hoge", "fuga", "piyo"}
// 順番が担保されないため、テストが失敗する
if diff := cmp.Diff(actual, expected); diff != "" {
t.Errorf("Diff: (-got +want)\n%s", diff)
}
// sliceではcmp.Diffで順序が考慮されてしまうのでSetに変換して比較する
expectedSet := make(map[string]struct{})
for _, v := range expected {
expectedSet[v] = struct{}{}
}
actualSet := make(map[string]struct{})
for _, v := range actual {
actualSet[v] = struct{}{}
}
// 順番が担保されるため、テストが成功する
if diff := cmp.Diff(actualSet, expectedSet); diff != "" {
t.Errorf("Diff: (-got +want)\n%s", diff)
}
}
请提供更多上下文说明或具体的句子,以便更好地把握需要重新表达的意思。
实现Set类型在Go中的选择。