1 Does an empty structure take up space?

In Go, we can use unsafe.Sizeof to calculate the number of bytes an instance of a data type needs to occupy.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
package main

import (
	"fmt"
	"unsafe"
)

func main() {
	fmt.Println(unsafe.Sizeof(struct{}{}))
}

Running the above example will output:

1
2
$ go run main.go
0

That is, an instance of the empty struct struct{} does not occupy any memory space.

2 The role of the empty structure

Because empty structs do not occupy memory space, they are widely used as placeholders in various scenarios. One is to save resources, and the other is that the empty struct itself has a strong semantic meaning that no value is needed here, only as a placeholder.

2.1 Implementing a Set

The Go language standard library does not provide an implementation of Set, and maps are usually used instead. In fact, for a set, only the keys of the map are needed, not the values. Even if the value is set to bool, it will take up an extra 1 byte, so assuming there are a million items in the map, that’s 1MB of wasted space.

Therefore, when using map as a set, you can define the value type as an empty structure and use it only as a placeholder.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
type Set map[string]struct{}

func (s Set) Has(key string) bool {
	_, ok := s[key]
	return ok
}

func (s Set) Add(key string) {
	s[key] = struct{}{}
}

func (s Set) Delete(key string) {
	delete(s, key)
}

func main() {
	s := make(Set)
	s.Add("Tom")
	s.Add("Sam")
	fmt.Println(s.Has("Tom"))
	fmt.Println(s.Has("Jack"))
}

2.2 Channels that do not send data (channel)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
func worker(chan struct{}) {
	<-ch
	fmt.Println("do something")
	close(ch)
}

func main() {
	ch := make(chan struct{})
	go worker(ch)
	ch <- struct{}{}
}

Sometimes a channel is used without sending any data, only to inform a subcoordinator goroutine to perform a task, or only to control a goroutine. In this case, it is appropriate to use an empty structure as a placeholder.

2.3 Structs containing only methods

1
2
3
4
5
6
7
8
9
type Door struct{}

func (d Door) Open() {
	fmt.Println("Open the door")
}

func (d Door) Close() {
	fmt.Println("Close the door")
}

In some scenarios, the structure contains only methods and not any fields. For example Door in the example above, in this case Door can in fact be replaced by any data structure. For example

1
2
type Door int
type Door bool

Either int or bool will waste extra memory, so it is most appropriate to declare the structure as empty in this case.


Reference https://geektutu.com/post/hpg-empty-struct.html