Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ A curated collection of idiomatic design & application patterns for Go language.

| Pattern | Description | Status |
|:-------:|:----------- |:------:|
| [Empty Struct](/idiom/empty-struct.md) | Uses a struct with no fields to clarify intent and reduce memory usage | ✔ |
| [Functional Options](/idiom/functional-options.md) | Allows creating clean APIs with sane defaults and idiomatic overrides | ✔ |

## Anti-Patterns
Expand Down
84 changes: 84 additions & 0 deletions idiom/empty-struct.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Empty Struct
The empty struct is a struct type with no fields.
It has a couple of interesting properties.

- Its size is zero bytes, so values of this type occupy no storage
- It is often used when no data needs to be stored, but the type itself conveys intent

## Implementation
### Zero Size
```go
package main

import (
"fmt"
"unsafe"
)

var i int16
var c complex128
var s struct{}

func main() {
fmt.Println(unsafe.Sizeof(i)) // 2 bytes
fmt.Println(unsafe.Sizeof(c)) // 16 bytes
fmt.Println(unsafe.Sizeof(s)) // 0 bytes
}
```


### Signal-only Channel
```go
package main

func main() {
done := make(chan struct{})

go func() {
// do work...
close(done)
}()

<-done
}
```

### Set
```go
type S map[string]struct{}

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

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

## Usage
### Signal-only Channel
```go
done := make(chan struct{})

go func() {
close(done)
}()

<-done // blocks until goroutine signals completion
```

### Set
```go
s := make(S)
s.Add("go")
s.Add("patterns")

fmt.Println(s.Has("go")) // true
fmt.Println(s.Has("rust")) // false
```

## Rules of Thumb
- Prefer `chan struct{}` over `chan bool` when no data needs to be sent
- Prefer `map[K]struct{}` over `map[K]bool` when implementing a set