Go doesn’t have a type for set . Some propose to use a map[T]bool to build a set of items of type T. For instance:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 set := make (map [int ]bool ) set[1 ] = true set[5 ] = true if set[1 ] { fmt.Println("1 is in the set" ) } if set[2 ] { fmt.Println("2 is in the set" ) } delete (set, 1 )for i := range set { fmt.Println(i) }
This has two drawbacks:
Values in the map must always be true, otherwise listing values doesn’t work (or requires an additional if). This is misleading.
Values in the map take some space (1 byte per key).
A better alternative is to use map[T]struct{} (a map with empty structs as values). For instance:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 set := make (map [int ]struct {}) set[1 ] = struct {}{} set[5 ] = struct {}{} if _, ok := set[1 ]; ok { fmt.Println("1 is in the set" ) } if _, ok := set[2 ]; ok { fmt.Println("2 is in the set" ) } delete (set, 1 )for i := range set { fmt.Println(i) }
benchmarks Some of you requested some benchmarks to know how much memory is saved by using struct{} instead of bool values. I ran this little test program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package mainimport ( "fmt" "testing" ) func benchmarkBool (b *testing.B) { s := make (map [int ]bool ) for i := 0 ; i < 10000 *b.N; i++ { s[2 *i] = true } } func benchmarkStruct (b *testing.B) { s := make (map [int ]struct {}) for i := 0 ; i < 10000 *b.N; i++ { s[2 *i] = struct {}{} } } func main () { boolRes := testing.Benchmark(benchmarkBool) fmt.Println("bool:" , boolRes.MemString()) structRes := testing.Benchmark(benchmarkStruct) fmt.Println("struct{}:" , structRes.MemString()) fmt.Println("AllocedBytesPerOp ratio:" , float32 (boolRes.AllocedBytesPerOp()) / float32 (structRes.AllocedBytesPerOp())) fmt.Println("AllocsPerOp ratio:" , float32 (boolRes.AllocsPerOp()) / float32 (structRes.AllocsPerOp())) }
allocs/op 表示每个 op 发生多少个不同的内存分配(单次迭代)。越小越好
B/op 是每个操作分配了多少字节。 越小越好
So you save 50% memory for int maps (on a 64-bit machine).