Why use struct{}{}

This article uses these constructs:

done := make(chan struct{}, 2)
done <- struct{}{}

Is struct{} an idiom for a type whose content does not matter, but its presence does?
Is it the smallest type? Does it take less space than bool, or byte? Is its size zero?
A ran a test, and I think the answer is yes to all:

package main

import (
    "fmt"
)

func main() {
    for i := 0; i < 100; i++ {
        a := make([]struct{}, 4000000000)
        fmt.Println(i, len(a))
    }
}

This program runs very quickly.
If I use byte instead of struct{}, the program gets stuck looking for memory.

An arrray of 0 size (such as [0]bool also has this property of zero size.

Yes, struct{} is the smallest type. I like to think of it like void in C but it’s actually instantiate-able. It is a struct but it also has no fields therefore takes no memory to be allocated. It’s useful for signalling completion or readiness. It’s also useful to implement a set type from a map a-la:

setOfIntegers := make(map[int]struct{})
2 Likes

You can read here a nice article about empty struct.

https://dave.cheney.net/2014/03/25/the-empty-struct

2 Likes

I miss Dave Cheney’s Go writings.

Good point about the set. So you’d use it like this:

	set := make(map[int]struct{})
	set[3] = struct{}{}
	if _, ok := set[3]; !ok {
		t.Fail()
	}

Or like this:

type Set[T comparable] map[T]struct{}

func (s Set[T]) Put(t T) {
	s[t] = struct{}{}
}

func (s Set[T]) Contains(t T) bool {
	_, ok := s[t]
	return ok
}

func main() {
	set := make(Set[int])
	set.Put(3)
	fmt.Printf("%v %v\n", set.Contains(3), set.Contains(1))
	fmt.Printf("%v %v\n", set[3], set[1])
}

1 Like