What is the function of an empty structure?
0. Introduction
This section will introduce some things about golang hollow structure, such as implementing set, notifying chan, limiting chan, etc. in addition, some pits will be exposed. Next, let's take an inventory.
1. Empty structure
The output below is 0. For empty structures, the size is 0, that is, it does not occupy any space. This feature is very popular in set and chan.
func main() { fmt.Println(unsafe.Sizeof(struct{}{})) }
2.set
In go, there is no self-contained set like c++ stl, which needs to be implemented by map.
type void struct{} type set map[string]void
This method is better than the set of map[string]bool. Of course, there are some mature set libraries on github, such as golang set.
3.chan
Scenario 1: notify task completion
We can use bool to express it, and the writing method is as follows:
package main import ( "fmt" "time" ) func worker(done chan bool) { fmt.Print("working...") time.Sleep(time.Second) fmt.Println("done") done <- true } func main() { done := make(chan bool, 1) go worker(done) <-done }
For the channel itself, it can be used to transfer data. Of course, for the data, the smaller the size, the better. For scenes without any data logic and useless data, empty structures can be used.
func worker(done chan struct{}) { fmt.Print("working...") // Send a value to notify that we're done. done <- struct{}{} } func main() { // Start a worker goroutine, giving it the channel to // notify on. done := make(chan struct{}, 1) go worker(done) // Block until we receive a notification from the // worker on the channel. <-done }
Scenario 2: timeout control
Use an empty structure + select statement.
// Use time After implementation func main() { done := do() select { case <-done: // logic case <-time.After(3 * time.Second): // timeout } } func do() <-chan struct{} { done := make(chan struct{}, 1) go func() { // do something // ... done <- struct{}{} }() return done }
Scenario 3: limit maximum concurrency
Limit maximum concurrency to 2
limits := make(chan struct{}, 2) for i := 0; i < 10; i++ { go func() { // When the buffer is full, it will block here limits <- struct{}{} do() <-limits }() }
4. Structure containing only methods
For example:
type Foo struct{} func (f Foo) Eat() { fmt.Println("foo eat") } func (f Foo) Run() { fmt.Println("foo run") }
5. Some issues
When comparing the addresses of empty structures, you will find that the addresses are the same, but one is false and the other is true. Can empty structures be compared?
func main() { a := new(struct{}) b := new(struct{}) println(a, b, a == b) c := new(struct{}) d := new(struct{}) fmt.Println(c, d) println(c, d, c == d) }
Output:
0xc00006cf57 0xc00006cf57 false 0x118c370 0x118c370 true &{} &{}
The reasons are explained in detail in the following article, which is briefly described here.
True explanation: if it escapes to the heap, the empty structure is allocated runtime by default The zerobase variable is a 0-byte base address specifically assigned to the heap. Therefore, both empty structures are runtime Zerobase, of course, is true.
False explanation: allocate to the stack. In the code optimization phase of the Go compiler, it will be optimized and directly return false.
https://eddycjy.com/posts/go/go-empty-struct/
End of this section