feat: add source hyperlinks (commit SHA permalinks) to all pattern files

Every source reference now links to the exact line in the golang/go
repo at commit 17bd5ab. Added PATTERN_COMPLETE sentinels.

Total: 154 hyperlinks across 10 topic files.
This commit is contained in:
Rodin
2026-04-30 14:42:20 -07:00
parent 99c0865e93
commit c8ed244a07
9 changed files with 172 additions and 144 deletions
+14 -10
View File
@@ -1,10 +1,12 @@
# API Conventions in the Go Standard Library # API Conventions in the Go Standard Library
**Source:** [golang/go](https://github.com/golang/go) at commit [`17bd5ab`](https://github.com/golang/go/tree/17bd5ab8c650155dd2bd09f7005726552639eea0)
## 1. The Must Pattern ## 1. The Must Pattern
**Pattern name:** MustXxx (Panic on Error) **Pattern name:** MustXxx (Panic on Error)
**Source citation:** `regexp/regexp.go` lines 310320, `text/template/helper.go` lines 1930 **Source citation:** [regexp/regexp.go#L310](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/regexp/regexp.go#L310), [text/template/helper.go#L19](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/text/template/helper.go#L19)
**What it does:** A function wraps a fallible constructor and panics if the error **What it does:** A function wraps a fallible constructor and panics if the error
is non-nil. Named `MustXxx` or `Must` (when wrapping a generic `(T, error)` pair). is non-nil. Named `MustXxx` or `Must` (when wrapping a generic `(T, error)` pair).
@@ -114,7 +116,7 @@ func Must(t *Template, err error) *Template {
**Pattern name:** Fallible Constructor + Must Wrapper **Pattern name:** Fallible Constructor + Must Wrapper
**Source citation:** `regexp/regexp.go` lines 130131, 310320 **Source citation:** [regexp/regexp.go#L130](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/regexp/regexp.go#L130), 310320
**What it does:** The real constructor returns `(*T, error)`. A parallel `Must` variant **What it does:** The real constructor returns `(*T, error)`. A parallel `Must` variant
wraps it for use in global variable initialization. wraps it for use in global variable initialization.
@@ -149,7 +151,7 @@ func MustCompile(str string) *Regexp {
**Pattern name:** WithContext Function Overload **Pattern name:** WithContext Function Overload
**Source citation:** `net/http/request.go` lines 867869, 894930 **Source citation:** [net/http/request.go#L867](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/request.go#L867), 894930
**What it does:** Provides two function variants: `NewRequest` (uses `context.Background()`) **What it does:** Provides two function variants: `NewRequest` (uses `context.Background()`)
and `NewRequestWithContext` (accepts an explicit context). The simple version delegates and `NewRequestWithContext` (accepts an explicit context). The simple version delegates
@@ -182,7 +184,7 @@ func NewRequestWithContext(ctx context.Context, method, url string, body io.Read
**Pattern name:** `*Options` Parameter — Nil Means Defaults **Pattern name:** `*Options` Parameter — Nil Means Defaults
**Source citation:** `log/slog/text_handler.go` lines 2842, `log/slog/handler.go` lines 135175 **Source citation:** [log/slog/text_handler.go#L28](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/log/slog/text_handler.go#L28), [log/slog/handler.go#L135](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/log/slog/handler.go#L135)
**What it does:** A constructor accepts a pointer to an options struct. If the pointer **What it does:** A constructor accepts a pointer to an options struct. If the pointer
is nil, all defaults apply. The constructor internally substitutes a zero-value struct. is nil, all defaults apply. The constructor internally substitutes a zero-value struct.
@@ -221,7 +223,7 @@ func NewTextHandler(w io.Writer, opts *HandlerOptions) *TextHandler {
**Pattern name:** Builder (Write Methods + String/Bytes Finalizer) **Pattern name:** Builder (Write Methods + String/Bytes Finalizer)
**Source citation:** `strings/builder.go` lines 14113 **Source citation:** [strings/builder.go#L14](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/strings/builder.go#L14)
**What it does:** A zero-value struct accumulates data via Write/WriteByte/WriteString **What it does:** A zero-value struct accumulates data via Write/WriteByte/WriteString
methods, then produces a final result via String(). The builder is not reusable after methods, then produces a final result via String(). The builder is not reusable after
@@ -264,7 +266,7 @@ func (b *Builder) String() string {
**Pattern name:** Convenience Wrappers over Configurable Core **Pattern name:** Convenience Wrappers over Configurable Core
**Source citation:** `os/file.go` lines 385415 **Source citation:** [os/file.go#L385](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/os/file.go#L385)
**What it does:** Simple functions (`Open`, `Create`) delegate to the fully configurable **What it does:** Simple functions (`Open`, `Create`) delegate to the fully configurable
`OpenFile` with pre-set flags. Users choose their level of control. `OpenFile` with pre-set flags. Users choose their level of control.
@@ -355,7 +357,7 @@ func OpenFile(name string, flag int, perm FileMode) (*File, error) {
**Pattern name:** Convenience Package Functions **Pattern name:** Convenience Package Functions
**Source citation:** `net/http/client.go` line 109, implied by `http.Get`, `http.Post` **Source citation:** [net/http/client.go#L109](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/client.go#L109), implied by `http.Get`, `http.Post`
**What it does:** Top-level functions like `http.Get(url)` call methods on the **What it does:** Top-level functions like `http.Get(url)` call methods on the
`DefaultClient`. Users can bypass by creating their own `Client`. `DefaultClient`. Users can bypass by creating their own `Client`.
@@ -384,7 +386,7 @@ var DefaultClient = &Client{}
**Pattern name:** RegisterXxx for Side-Effect Imports **Pattern name:** RegisterXxx for Side-Effect Imports
**Source citation:** `crypto/crypto.go` lines 145150 **Source citation:** [crypto/crypto.go#L145](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/crypto/crypto.go#L145)
**What it does:** A `RegisterHash(h Hash, f func() hash.Hash)` function allows **What it does:** A `RegisterHash(h Hash, f func() hash.Hash)` function allows
algorithm implementations in sub-packages to register themselves via `init()`. algorithm implementations in sub-packages to register themselves via `init()`.
@@ -415,7 +417,7 @@ func RegisterHash(h Hash, f func() hash.Hash) {
**Pattern name:** Close vs Shutdown (Immediate vs Graceful) **Pattern name:** Close vs Shutdown (Immediate vs Graceful)
**Source citation:** `net/http/server.go` lines 31713220 (Close), 3221+ (Shutdown) **Source citation:** [net/http/server.go#L3171](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L3171) (Close), 3221+ (Shutdown)
**What it does:** Provides both `Close()` (immediate, forceful) and `Shutdown(ctx)` **What it does:** Provides both `Close()` (immediate, forceful) and `Shutdown(ctx)`
(graceful, waits for in-flight requests). The context on Shutdown provides a (graceful, waits for in-flight requests). The context on Shutdown provides a
@@ -530,7 +532,7 @@ func (s *Server) Shutdown(ctx context.Context) error {
**Pattern name:** NewXxx Returning Channel-Bearing Struct **Pattern name:** NewXxx Returning Channel-Bearing Struct
**Source citation:** `time/tick.go` lines 1645, `time/sleep.go` lines 89155 **Source citation:** [time/tick.go#L16](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/time/tick.go#L16), [time/sleep.go#L89](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/time/sleep.go#L89)
**What it does:** `NewTicker(d)` and `NewTimer(d)` return structs with a `C <-chan Time` **What it does:** `NewTicker(d)` and `NewTimer(d)` return structs with a `C <-chan Time`
field. Consumers select on the channel to receive time events. field. Consumers select on the channel to receive time events.
@@ -561,3 +563,5 @@ func NewTicker(d Duration) *Ticker {
return t return t
} }
``` ```
<!-- PATTERN_COMPLETE -->
+31 -29
View File
@@ -6,10 +6,10 @@ Patterns extracted from the Go standard library source code.
## 1. sync.Mutex — The Basic Lock ## 1. sync.Mutex — The Basic Lock
### Source: `src/sync/mutex.go:18-34`, `src/sync/mutex.go:42-67` ### Source: [src/sync/mutex.go#L18](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/mutex.go#L18), [src/sync/mutex.go#L42](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/mutex.go#L42)
```go ```go
// src/sync/mutex.go:18-34 // [src/sync/mutex.go#L18](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/mutex.go#L18)
// A Mutex is a mutual exclusion lock. // A Mutex is a mutual exclusion lock.
// The zero value for a Mutex is an unlocked mutex. // The zero value for a Mutex is an unlocked mutex.
// //
@@ -19,13 +19,13 @@ type Mutex struct {
mu isync.Mutex mu isync.Mutex
} }
// src/sync/mutex.go:36-39 // [src/sync/mutex.go#L36](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/mutex.go#L36)
type Locker interface { type Locker interface {
Lock() Lock()
Unlock() Unlock()
} }
// src/sync/mutex.go:43-46 // [src/sync/mutex.go#L43](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/mutex.go#L43)
func (m *Mutex) Lock() { func (m *Mutex) Lock() {
m.mu.Lock() m.mu.Lock()
} }
@@ -146,24 +146,24 @@ mu.Unlock()
## 2. sync.Once — Exactly-Once Initialization ## 2. sync.Once — Exactly-Once Initialization
### Source: `src/sync/once.go:12-36`, `src/sync/once.go:56-79` ### Source: [src/sync/once.go#L12](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/once.go#L12), [src/sync/once.go#L56](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/once.go#L56)
```go ```go
// src/sync/once.go:12-23 // [src/sync/once.go#L12](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/once.go#L12)
type Once struct { type Once struct {
_ noCopy _ noCopy
done atomic.Bool done atomic.Bool
m Mutex m Mutex
} }
// src/sync/once.go:56-63 // [src/sync/once.go#L56](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/once.go#L56)
func (o *Once) Do(f func()) { func (o *Once) Do(f func()) {
if !o.done.Load() { if !o.done.Load() {
o.doSlow(f) o.doSlow(f)
} }
} }
// src/sync/once.go:65-72 // [src/sync/once.go#L65](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/once.go#L65)
func (o *Once) doSlow(f func()) { func (o *Once) doSlow(f func()) {
o.m.Lock() o.m.Lock()
defer o.m.Unlock() defer o.m.Unlock()
@@ -301,10 +301,10 @@ once.Do(func() {
## 3. sync.WaitGroup — Waiting for Goroutine Completion ## 3. sync.WaitGroup — Waiting for Goroutine Completion
### Source: `src/sync/waitgroup.go:14-43`, `src/sync/waitgroup.go:236-260` ### Source: [src/sync/waitgroup.go#L14](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/waitgroup.go#L14), [src/sync/waitgroup.go#L236](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/waitgroup.go#L236)
```go ```go
// src/sync/waitgroup.go:14-43 // [src/sync/waitgroup.go#L14](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/waitgroup.go#L14)
// Typically, a main goroutine will start tasks by calling WaitGroup.Go // Typically, a main goroutine will start tasks by calling WaitGroup.Go
// and then wait for all tasks to complete by calling WaitGroup.Wait: // and then wait for all tasks to complete by calling WaitGroup.Wait:
// //
@@ -322,7 +322,7 @@ type WaitGroup struct {
### Go 1.25+: WaitGroup.Go ### Go 1.25+: WaitGroup.Go
```go ```go
// src/sync/waitgroup.go:236-260 // [src/sync/waitgroup.go#L236](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/waitgroup.go#L236)
func (wg *WaitGroup) Go(f func()) { func (wg *WaitGroup) Go(f func()) {
wg.Add(1) wg.Add(1)
go func() { go func() {
@@ -374,10 +374,10 @@ wg.Wait()
## 4. sync.Pool — Object Reuse for GC Pressure ## 4. sync.Pool — Object Reuse for GC Pressure
### Source: `src/sync/pool.go:44-63` ### Source: [src/sync/pool.go#L44](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/pool.go#L44)
```go ```go
// src/sync/pool.go:44-63 // [src/sync/pool.go#L44](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/pool.go#L44)
// Pool's purpose is to cache allocated but unused items for later reuse, // Pool's purpose is to cache allocated but unused items for later reuse,
// relieving pressure on the garbage collector. That is, it makes it easy to // relieving pressure on the garbage collector. That is, it makes it easy to
// build efficient, thread-safe free lists. // build efficient, thread-safe free lists.
@@ -439,15 +439,15 @@ pool.Put(buf) // still has data from last use
## 5. Channel as Done Signal (Context Pattern) ## 5. Channel as Done Signal (Context Pattern)
### Source: `src/context/context.go:83-100` (Done channel), `src/io/pipe.go:42-45` ### Source: [src/context/context.go#L83](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/context/context.go#L83) (Done channel), [src/io/pipe.go#L42](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/pipe.go#L42)
```go ```go
// src/context/context.go:83-100 // [src/context/context.go#L83](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/context/context.go#L83)
// Done returns a channel that's closed when work done on behalf of this // Done returns a channel that's closed when work done on behalf of this
// context should be canceled. // context should be canceled.
Done() <-chan struct{} Done() <-chan struct{}
// src/io/pipe.go:42-45 // [src/io/pipe.go#L42](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/pipe.go#L42)
type pipe struct { type pipe struct {
once sync.Once once sync.Once
done chan struct{} // closed on pipe close done chan struct{} // closed on pipe close
@@ -583,10 +583,10 @@ close(done)
## 6. Context Propagation Rules ## 6. Context Propagation Rules
### Source: `src/context/context.go:37-48` ### Source: [src/context/context.go#L37](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/context/context.go#L37)
```go ```go
// src/context/context.go:37-48 // [src/context/context.go#L37](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/context/context.go#L37)
// Do not store Contexts inside a struct type; instead, pass a Context // Do not store Contexts inside a struct type; instead, pass a Context
// explicitly to each function that needs it. The Context should be the first // explicitly to each function that needs it. The Context should be the first
// parameter, typically named ctx: // parameter, typically named ctx:
@@ -622,10 +622,10 @@ func doWork(data Data, ctx context.Context) // wrong position
## 7. Context Cancellation with Timeout ## 7. Context Cancellation with Timeout
### Source: `src/net/http/server.go:4007-4050` (TimeoutHandler) ### Source: [src/net/http/server.go#L4007](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L4007) (TimeoutHandler)
```go ```go
// src/net/http/server.go:4011-4050 // [src/net/http/server.go#L4011](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L4011)
func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) { func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) {
ctx, cancelCtx := context.WithTimeout(r.Context(), h.dt) ctx, cancelCtx := context.WithTimeout(r.Context(), h.dt)
defer cancelCtx() defer cancelCtx()
@@ -675,10 +675,10 @@ func longWork(ctx context.Context) {
## 8. Select with Non-Blocking Check ## 8. Select with Non-Blocking Check
### Source: `src/io/pipe.go:51-60` ### Source: [src/io/pipe.go#L51](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/pipe.go#L51)
```go ```go
// src/io/pipe.go:51-60 // [src/io/pipe.go#L51](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/pipe.go#L51)
func (p *pipe) read(b []byte) (n int, err error) { func (p *pipe) read(b []byte) (n int, err error) {
select { select {
case <-p.done: case <-p.done:
@@ -719,17 +719,17 @@ for {
## 9. Channel Pipeline (io.Pipe) ## 9. Channel Pipeline (io.Pipe)
### Source: `src/io/pipe.go:38-45`, `src/io/pipe.go:195-205` ### Source: [src/io/pipe.go#L38](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/pipe.go#L38), [src/io/pipe.go#L195](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/pipe.go#L195)
```go ```go
// src/io/pipe.go:38-45 // [src/io/pipe.go#L38](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/pipe.go#L38)
type pipe struct { type pipe struct {
wrCh chan []byte // writer sends data slices wrCh chan []byte // writer sends data slices
rdCh chan int // reader returns bytes consumed rdCh chan int // reader returns bytes consumed
done chan struct{} done chan struct{}
} }
// src/io/pipe.go:195-205 // [src/io/pipe.go#L195](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/pipe.go#L195)
func Pipe() (*PipeReader, *PipeWriter) { func Pipe() (*PipeReader, *PipeWriter) {
pw := &PipeWriter{r: PipeReader{pipe: pipe{ pw := &PipeWriter{r: PipeReader{pipe: pipe{
wrCh: make(chan []byte), // unbuffered wrCh: make(chan []byte), // unbuffered
@@ -868,10 +868,10 @@ func produce() <-chan int {
## 10. Background Worker with Context Shutdown ## 10. Background Worker with Context Shutdown
### Source: `src/database/sql/sql.go:836-843` ### Source: [src/database/sql/sql.go#L836](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/database/sql/sql.go#L836)
```go ```go
// src/database/sql/sql.go:836-843 // [src/database/sql/sql.go#L836](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/database/sql/sql.go#L836)
func OpenDB(c driver.Connector) *DB { func OpenDB(c driver.Connector) *DB {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
db := &DB{ db := &DB{
@@ -903,10 +903,10 @@ go func() {
## 11. noCopy — Preventing Value Copies ## 11. noCopy — Preventing Value Copies
### Source: `src/sync/cond.go:120-126` ### Source: [src/sync/cond.go#L120](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/cond.go#L120)
```go ```go
// src/sync/cond.go:120-126 // [src/sync/cond.go#L120](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/cond.go#L120)
type noCopy struct{} type noCopy struct{}
// Lock is a no-op used by -copylocks checker from `go vet`. // Lock is a no-op used by -copylocks checker from `go vet`.
@@ -947,3 +947,5 @@ func doWork(wg *sync.WaitGroup) {
| Backpressure between producer/consumer | Unbuffered channels | | Backpressure between producer/consumer | Unbuffered channels |
| Long-lived background worker | Goroutine + context cancellation | | Long-lived background worker | Goroutine + context cancellation |
| Prevent struct copying | Embed `noCopy` field | | Prevent struct copying | Embed `noCopy` field |
<!-- PATTERN_COMPLETE -->
+13 -9
View File
@@ -1,10 +1,12 @@
# Documentation Patterns in the Go Standard Library # Documentation Patterns in the Go Standard Library
**Source:** [golang/go](https://github.com/golang/go) at commit [`17bd5ab`](https://github.com/golang/go/tree/17bd5ab8c650155dd2bd09f7005726552639eea0)
## 1. Package Documentation (doc.go or Package Comment) ## 1. Package Documentation (doc.go or Package Comment)
**Pattern name:** Package Doc Comment **Pattern name:** Package Doc Comment
**Source citation:** `net/http/doc.go` lines 630, `os/file.go` lines 543, `log/slog/doc.go` lines 630 **Source citation:** [net/http/doc.go#L6](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/doc.go#L6), [os/file.go#L5](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/os/file.go#L5), [log/slog/doc.go#L6](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/log/slog/doc.go#L6)
**What it does:** The first file in a package (by convention `doc.go`, or the main **What it does:** The first file in a package (by convention `doc.go`, or the main
source file) starts with a `// Package xxx ...` comment that explains the package's source file) starts with a `// Package xxx ...` comment that explains the package's
@@ -57,7 +59,7 @@ expressed as key-value pairs.
**Pattern name:** `# Heading` in Doc Comments **Pattern name:** `# Heading` in Doc Comments
**Source citation:** `os/file.go` lines 3743, `net/http/doc.go` (multiple sections) **Source citation:** [os/file.go#L37](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/os/file.go#L37), `net/http/doc.go` (multiple sections)
**What it does:** Uses `# Section Name` within the package doc comment to organize **What it does:** Uses `# Section Name` within the package doc comment to organize
long documentation into navigable sections. long documentation into navigable sections.
@@ -84,7 +86,7 @@ too many sections (fragmenting simple docs).
**Pattern name:** `// TypeName verb...` or `// FuncName verb...` **Pattern name:** `// TypeName verb...` or `// FuncName verb...`
**Source citation:** `net/http/server.go` lines 6482 (Handler), `bufio/scan.go` lines 1427 (Scanner) **Source citation:** [net/http/server.go#L64](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L64) (Handler), [bufio/scan.go#L14](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/bufio/scan.go#L14) (Scanner)
**What it does:** Every exported identifier's doc comment starts with the identifier **What it does:** Every exported identifier's doc comment starts with the identifier
name, followed by a verb phrase describing what it does or represents. name, followed by a verb phrase describing what it does or represents.
@@ -125,7 +127,7 @@ the comment entirely.
**Pattern name:** `[TypeName]`, `[Package.Symbol]`, `[Method]` Links **Pattern name:** `[TypeName]`, `[Package.Symbol]`, `[Method]` Links
**Source citation:** `net/http/server.go` lines 6570, `os/file.go` line 9 **Source citation:** [net/http/server.go#L65](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L65), [os/file.go#L9](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/os/file.go#L9)
**What it does:** Doc comments use `[SymbolName]` to create hyperlinks to other **What it does:** Doc comments use `[SymbolName]` to create hyperlinks to other
identifiers. These render as clickable links on pkg.go.dev. identifiers. These render as clickable links on pkg.go.dev.
@@ -158,7 +160,7 @@ over-linking (every mention of every type).
**Pattern name:** `func ExampleXxx()` / `func ExampleType_Method()` **Pattern name:** `func ExampleXxx()` / `func ExampleType_Method()`
**Source citation:** `regexp/example_test.go` lines 1328, `net/http/example_handle_test.go` lines 1631 **Source citation:** [regexp/example_test.go#L13](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/regexp/example_test.go#L13), [net/http/example_handle_test.go#L16](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/example_handle_test.go#L16)
**What it does:** Functions named `Example`, `ExampleXxx`, or `ExampleType_Method` **What it does:** Functions named `Example`, `ExampleXxx`, or `ExampleType_Method`
in `_test.go` files serve as both executable tests and documentation. They include in `_test.go` files serve as both executable tests and documentation. They include
@@ -278,7 +280,7 @@ func ExampleHandle() {
**Pattern name:** Indented Code Blocks in Comments **Pattern name:** Indented Code Blocks in Comments
**Source citation:** `os/file.go` lines 1735, `time/time.go` lines 928933 **Source citation:** [os/file.go#L17](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/os/file.go#L17), [time/time.go#L928](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/time/time.go#L928)
**What it does:** Doc comments include indented code snippets (4 spaces) that render **What it does:** Doc comments include indented code snippets (4 spaces) that render
as preformatted code blocks in godoc. as preformatted code blocks in godoc.
@@ -318,7 +320,7 @@ for inline (use Example functions instead); examples that reference unexported s
**Pattern name:** `// Deprecated: ...` in Doc Comments **Pattern name:** `// Deprecated: ...` in Doc Comments
**Source citation:** `net/http/server.go` line 57 (ErrWriteAfterFlush), `os/file.go` lines 9395 **Source citation:** [net/http/server.go#L57](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L57) (ErrWriteAfterFlush), [os/file.go#L93](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/os/file.go#L93)
**What it does:** A paragraph starting with `Deprecated:` marks an identifier as **What it does:** A paragraph starting with `Deprecated:` marks an identifier as
deprecated and explains what to use instead. deprecated and explains what to use instead.
@@ -399,7 +401,7 @@ ErrWriteAfterFlush = errors.New("unused")
**Pattern name:** "If there is an error, it will be of type [*XxxError]" **Pattern name:** "If there is an error, it will be of type [*XxxError]"
**Source citation:** `os/file.go` lines 388, 406 **Source citation:** [os/file.go#L388](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/os/file.go#L388), 406
**What it does:** Functions document the concrete error type they return, enabling **What it does:** Functions document the concrete error type they return, enabling
callers to type-assert for additional context. callers to type-assert for additional context.
@@ -428,7 +430,7 @@ func Open(name string) (*File, error) {
**Pattern name:** "Safe for concurrent use" / Concurrency Guarantees **Pattern name:** "Safe for concurrent use" / Concurrency Guarantees
**Source citation:** `net/http/transport.go` lines 7980, `os/types.go` line 17, `regexp/regexp.go` lines 7779 **Source citation:** [net/http/transport.go#L79](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/transport.go#L79), [os/types.go#L17](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/os/types.go#L17), [regexp/regexp.go#L77](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/regexp/regexp.go#L77)
**What it does:** Doc comments explicitly state the concurrency safety of a type **What it does:** Doc comments explicitly state the concurrency safety of a type
or note exceptions where concurrent use is not safe. or note exceptions where concurrent use is not safe.
@@ -454,3 +456,5 @@ concurrent use by multiple goroutines").
// A Regexp is safe for concurrent use by multiple goroutines, // A Regexp is safe for concurrent use by multiple goroutines,
// except for configuration methods, such as [Regexp.Longest]. // except for configuration methods, such as [Regexp.Longest].
``` ```
<!-- PATTERN_COMPLETE -->
+27 -25
View File
@@ -6,21 +6,21 @@ Patterns extracted from the Go standard library source code.
## 1. Sentinel Errors ## 1. Sentinel Errors
### Source: `src/io/io.go:40-43` (EOF), `src/errors/errors.go:81-83` (ErrUnsupported) ### Source: [src/io/io.go#L40](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L40) (EOF), [src/errors/errors.go#L81](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/errors/errors.go#L81) (ErrUnsupported)
```go ```go
// src/io/io.go:40-43 // [src/io/io.go#L40](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L40)
// EOF is the error returned by Read when no more input is available. // EOF is the error returned by Read when no more input is available.
// (Read must return EOF itself, not an error wrapping EOF, // (Read must return EOF itself, not an error wrapping EOF,
// because callers will test for EOF using ==.) // because callers will test for EOF using ==.)
var EOF = errors.New("EOF") var EOF = errors.New("EOF")
// src/io/io.go:47-49 // [src/io/io.go#L47](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L47)
var ErrUnexpectedEOF = errors.New("unexpected EOF") var ErrUnexpectedEOF = errors.New("unexpected EOF")
``` ```
```go ```go
// src/errors/errors.go:81-83 // [src/errors/errors.go#L81](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/errors/errors.go#L81)
var ErrUnsupported = New("unsupported operation") var ErrUnsupported = New("unsupported operation")
``` ```
@@ -132,15 +132,15 @@ func Read() error {
## 2. errors.New — Minimal Error Construction ## 2. errors.New — Minimal Error Construction
### Source: `src/errors/errors.go:62-69` ### Source: [src/errors/errors.go#L62](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/errors/errors.go#L62)
```go ```go
// src/errors/errors.go:62-64 // [src/errors/errors.go#L62](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/errors/errors.go#L62)
func New(text string) error { func New(text string) error {
return &errorString{text} return &errorString{text}
} }
// src/errors/errors.go:66-69 // [src/errors/errors.go#L66](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/errors/errors.go#L66)
type errorString struct { type errorString struct {
s string s string
} }
@@ -177,10 +177,10 @@ func doThing() error {
## 3. Error Wrapping with fmt.Errorf and %w ## 3. Error Wrapping with fmt.Errorf and %w
### Source: `src/fmt/errors.go:13-23`, `src/fmt/errors.go:70-80` ### Source: [src/fmt/errors.go#L13](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/fmt/errors.go#L13), [src/fmt/errors.go#L70](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/fmt/errors.go#L70)
```go ```go
// src/fmt/errors.go:13-23 // [src/fmt/errors.go#L13](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/fmt/errors.go#L13)
// Errorf formats according to a format specifier and returns the string // Errorf formats according to a format specifier and returns the string
// as a value that satisfies error. // as a value that satisfies error.
// //
@@ -190,7 +190,7 @@ func doThing() error {
// Unwrap method returning a []error containing all the %w operands. // Unwrap method returning a []error containing all the %w operands.
func Errorf(format string, a ...any) (err error) { ... } func Errorf(format string, a ...any) (err error) { ... }
// src/fmt/errors.go:70-80 // [src/fmt/errors.go#L70](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/fmt/errors.go#L70)
type wrapError struct { type wrapError struct {
msg string msg string
err error err error
@@ -310,10 +310,10 @@ return fmt.Errorf("internal: %w", internalErr) // now callers depend on interna
## 4. errors.Is — Checking Error Identity Through Chains ## 4. errors.Is — Checking Error Identity Through Chains
### Source: `src/errors/wrap.go:30-44` ### Source: [src/errors/wrap.go#L30](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/errors/wrap.go#L30)
```go ```go
// src/errors/wrap.go:30-44 // [src/errors/wrap.go#L30](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/errors/wrap.go#L30)
func Is(err, target error) bool { func Is(err, target error) bool {
if err == nil || target == nil { if err == nil || target == nil {
return err == target return err == target
@@ -377,10 +377,10 @@ if errors.Is(err, os.ErrNotExist) { ... } // works through wrapping
## 5. errors.As — Extracting Error Types Through Chains ## 5. errors.As — Extracting Error Types Through Chains
### Source: `src/errors/wrap.go:96-120` ### Source: [src/errors/wrap.go#L96](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/errors/wrap.go#L96)
```go ```go
// src/errors/wrap.go:96-120 // [src/errors/wrap.go#L96](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/errors/wrap.go#L96)
func As(err error, target any) bool { func As(err error, target any) bool {
if err == nil { if err == nil {
return false return false
@@ -406,7 +406,7 @@ if errors.As(err, &pathErr) {
### Go 1.24+: errors.AsType (generic version) ### Go 1.24+: errors.AsType (generic version)
From `src/errors/errors.go:48-56` doc: From [src/errors/errors.go#L48](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/errors/errors.go#L48) doc:
```go ```go
if perr, ok := errors.AsType[*fs.PathError](err); ok { if perr, ok := errors.AsType[*fs.PathError](err); ok {
fmt.Println(perr.Path) fmt.Println(perr.Path)
@@ -428,10 +428,10 @@ if errors.As(err, &pathErr) { ... } // works through wrapping
## 6. errors.Join — Multi-Error Aggregation ## 6. errors.Join — Multi-Error Aggregation
### Source: `src/errors/join.go:20-39` ### Source: [src/errors/join.go#L20](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/errors/join.go#L20)
```go ```go
// src/errors/join.go:20-39 // [src/errors/join.go#L20](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/errors/join.go#L20)
func Join(errs ...error) error { func Join(errs ...error) error {
n := 0 n := 0
for _, err := range errs { for _, err := range errs {
@@ -555,7 +555,7 @@ return lastErr
## 7. Custom Is() Method — Equivalence Classes ## 7. Custom Is() Method — Equivalence Classes
### Source: `src/errors/wrap.go:42-44` (doc comment), `src/context/context.go:177-179` ### Source: [src/errors/wrap.go#L42](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/errors/wrap.go#L42) (doc comment), [src/context/context.go#L177](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/context/context.go#L177)
From the `errors.Is` doc: From the `errors.Is` doc:
```go ```go
@@ -569,7 +569,7 @@ From the `errors.Is` doc:
Real example from context: Real example from context:
```go ```go
// src/context/context.go:177-179 // [src/context/context.go#L177](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/context/context.go#L177)
type deadlineExceededError struct{} type deadlineExceededError struct{}
func (deadlineExceededError) Error() string { return "context deadline exceeded" } func (deadlineExceededError) Error() string { return "context deadline exceeded" }
@@ -594,10 +594,10 @@ func (e MyError) Is(target error) bool {
## 8. Error Wrapping in Custom Types (Unwrap pattern) ## 8. Error Wrapping in Custom Types (Unwrap pattern)
### Source: `src/encoding/json/encode.go:276-293` ### Source: [src/encoding/json/encode.go#L276](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/encoding/json/encode.go#L276)
```go ```go
// src/encoding/json/encode.go:276-282 // [src/encoding/json/encode.go#L276](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/encoding/json/encode.go#L276)
type MarshalerError struct { type MarshalerError struct {
Type reflect.Type Type reflect.Type
Err error Err error
@@ -650,10 +650,10 @@ func (e *MyError) Error() string { return e.Err.Error() }
## 9. ErrUnsupported — Feature Detection via Errors ## 9. ErrUnsupported — Feature Detection via Errors
### Source: `src/errors/errors.go:76-83` ### Source: [src/errors/errors.go#L76](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/errors/errors.go#L76)
```go ```go
// src/errors/errors.go:76-83 // [src/errors/errors.go#L76](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/errors/errors.go#L76)
// ErrUnsupported indicates that a requested operation cannot be performed, // ErrUnsupported indicates that a requested operation cannot be performed,
// because it is unsupported. // because it is unsupported.
// //
@@ -685,10 +685,10 @@ return errors.ErrUnsupported // no info about what operation or why
## 10. Error String Conventions ## 10. Error String Conventions
### Source: `src/net/http/server.go:39-56` ### Source: [src/net/http/server.go#L39](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L39)
```go ```go
// src/net/http/server.go:39-56 // [src/net/http/server.go#L39](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L39)
var ( var (
ErrHijacked = errors.New("http: connection has been hijacked") ErrHijacked = errors.New("http: connection has been hijacked")
ErrContentLength = errors.New("http: wrote more than the declared Content-Length") ErrContentLength = errors.New("http: wrote more than the declared Content-Length")
@@ -742,3 +742,5 @@ Is this a specific, well-known condition?
| Aggregate multiple errors | `errors.Join(err1, err2)` | | Aggregate multiple errors | `errors.Join(err1, err2)` |
| Make custom types traversable | Implement `Unwrap() error` | | Make custom types traversable | Implement `Unwrap() error` |
| Define error equivalence | Implement `Is(error) bool` | | Define error equivalence | Implement `Is(error) bool` |
<!-- PATTERN_COMPLETE -->
+30 -28
View File
@@ -6,22 +6,22 @@ Patterns extracted from the Go standard library source code.
## 1. Small Interfaces (1-2 Methods) ## 1. Small Interfaces (1-2 Methods)
### Source: `src/io/io.go:80-92` (Reader), `93-103` (Writer), `105-109` (Closer) ### Source: [src/io/io.go#L80](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L80) (Reader), `93-103` (Writer), `105-109` (Closer)
Go's most powerful interfaces have exactly **one method**: Go's most powerful interfaces have exactly **one method**:
```go ```go
// src/io/io.go:80-92 // [src/io/io.go#L80](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L80)
type Reader interface { type Reader interface {
Read(p []byte) (n int, err error) Read(p []byte) (n int, err error)
} }
// src/io/io.go:93-103 // [src/io/io.go#L93](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L93)
type Writer interface { type Writer interface {
Write(p []byte) (n int, err error) Write(p []byte) (n int, err error)
} }
// src/io/io.go:105-109 // [src/io/io.go#L105](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L105)
type Closer interface { type Closer interface {
Close() error Close() error
} }
@@ -120,30 +120,30 @@ Large interfaces are hard to implement, hard to mock, and couple consumers to ca
## 2. Interface Composition ## 2. Interface Composition
### Source: `src/io/io.go:131-155` ### Source: [src/io/io.go#L131](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L131)
Compose small interfaces into larger ones only when needed: Compose small interfaces into larger ones only when needed:
```go ```go
// src/io/io.go:131-134 // [src/io/io.go#L131](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L131)
type ReadWriter interface { type ReadWriter interface {
Reader Reader
Writer Writer
} }
// src/io/io.go:136-139 // [src/io/io.go#L136](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L136)
type ReadCloser interface { type ReadCloser interface {
Reader Reader
Closer Closer
} }
// src/io/io.go:141-144 // [src/io/io.go#L141](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L141)
type WriteCloser interface { type WriteCloser interface {
Writer Writer
Closer Closer
} }
// src/io/io.go:146-150 // [src/io/io.go#L146](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L146)
type ReadWriteCloser interface { type ReadWriteCloser interface {
Reader Reader
Writer Writer
@@ -168,13 +168,13 @@ func processData(rw ReadWriteCloser) {
## 3. Accept Interfaces, Return Structs ## 3. Accept Interfaces, Return Structs
### Source: `src/io/io.go:461` (LimitReader), `src/io/io.go:618` (TeeReader) ### Source: [src/io/io.go#L461](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L461) (LimitReader), [src/io/io.go#L618](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L618) (TeeReader)
```go ```go
// src/io/io.go:461 // src/io/io.go:461
func LimitReader(r Reader, n int64) Reader { return &LimitedReader{r, n} } func LimitReader(r Reader, n int64) Reader { return &LimitedReader{r, n} }
// src/io/io.go:467-471 // [src/io/io.go#L467](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L467)
type LimitedReader struct { type LimitedReader struct {
R Reader // underlying reader R Reader // underlying reader
N int64 // max bytes remaining N int64 // max bytes remaining
@@ -182,7 +182,7 @@ type LimitedReader struct {
``` ```
```go ```go
// src/io/io.go:618-620 // [src/io/io.go#L618](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L618)
func TeeReader(r Reader, w Writer) Reader { func TeeReader(r Reader, w Writer) Reader {
return &teeReader{r, w} return &teeReader{r, w}
} }
@@ -272,7 +272,7 @@ func NewServer() ServerInterface // hides useful config fields
## 4. Interface Satisfaction as a Compile-Time Check ## 4. Interface Satisfaction as a Compile-Time Check
### Source: `src/io/io.go:645`, `src/net/http/server.go:4071` ### Source: [src/io/io.go#L645](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L645), [src/net/http/server.go#L4071](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L4071)
```go ```go
// src/io/io.go:645 // src/io/io.go:645
@@ -299,10 +299,10 @@ func doSomething(w ResponseWriter) {
## 5. Interface-Based Polymorphism (sort.Interface) ## 5. Interface-Based Polymorphism (sort.Interface)
### Source: `src/sort/sort.go:16-41` ### Source: [src/sort/sort.go#L16](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sort/sort.go#L16)
```go ```go
// src/sort/sort.go:16-41 // [src/sort/sort.go#L16](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sort/sort.go#L16)
type Interface interface { type Interface interface {
Len() int Len() int
Less(i, j int) bool Less(i, j int) bool
@@ -328,17 +328,17 @@ Note: Since Go 1.21, `slices.SortFunc` is preferred for slices (generic + faster
## 6. The Adapter Pattern (HandlerFunc) ## 6. The Adapter Pattern (HandlerFunc)
### Source: `src/net/http/server.go:2334-2342` ### Source: [src/net/http/server.go#L2334](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L2334)
```go ```go
// src/net/http/server.go:2334-2338 // [src/net/http/server.go#L2334](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L2334)
// The HandlerFunc type is an adapter to allow the use of // The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function // ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a // with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f. // Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request) type HandlerFunc func(ResponseWriter, *Request)
// src/net/http/server.go:2341-2342 // [src/net/http/server.go#L2341](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L2341)
// ServeHTTP calls f(w, r). // ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r) f(w, r)
@@ -436,15 +436,15 @@ func (h myHandler) ServeHTTP(w ResponseWriter, r *Request) {
## 7. Optional Interfaces (Runtime Feature Detection) ## 7. Optional Interfaces (Runtime Feature Detection)
### Source: `src/net/http/server.go:165-175` (Flusher), `src/net/http/server.go:183-206` (Hijacker) ### Source: [src/net/http/server.go#L165](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L165) (Flusher), [src/net/http/server.go#L183](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L183) (Hijacker)
```go ```go
// src/net/http/server.go:165-170 // [src/net/http/server.go#L165](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L165)
type Flusher interface { type Flusher interface {
Flush() Flush()
} }
// src/net/http/server.go:183-206 // [src/net/http/server.go#L183](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L183)
type Hijacker interface { type Hijacker interface {
Hijack() (net.Conn, *bufio.ReadWriter, error) Hijack() (net.Conn, *bufio.ReadWriter, error)
} }
@@ -564,10 +564,10 @@ type ResponseWriter interface {
## 8. The Stringer Interface (Convention-Based Behavior) ## 8. The Stringer Interface (Convention-Based Behavior)
### Source: `src/fmt/print.go:63-66` ### Source: [src/fmt/print.go#L63](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/fmt/print.go#L63)
```go ```go
// src/fmt/print.go:63-66 // [src/fmt/print.go#L63](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/fmt/print.go#L63)
type Stringer interface { type Stringer interface {
String() string String() string
} }
@@ -596,10 +596,10 @@ func printThing(v any) string {
## 9. Interface Upgrade Pattern (WriterTo/ReaderFrom in io.Copy) ## 9. Interface Upgrade Pattern (WriterTo/ReaderFrom in io.Copy)
### Source: `src/io/io.go:410-417` ### Source: [src/io/io.go#L410](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L410)
```go ```go
// src/io/io.go:410-417 // [src/io/io.go#L410](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L410)
func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) { func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
// If the reader has a WriteTo method, use it to do the copy. // If the reader has a WriteTo method, use it to do the copy.
// Avoids an allocation and a copy. // Avoids an allocation and a copy.
@@ -632,15 +632,15 @@ func Copy(dst Writer, src Reader) {
## 10. The driver.Driver Pattern (Plugin Interfaces) ## 10. The driver.Driver Pattern (Plugin Interfaces)
### Source: `src/database/sql/driver/driver.go:85-97`, `104-112` ### Source: [src/database/sql/driver/driver.go#L85](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/database/sql/driver/driver.go#L85), `104-112`
```go ```go
// src/database/sql/driver/driver.go:85-97 // [src/database/sql/driver/driver.go#L85](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/database/sql/driver/driver.go#L85)
type Driver interface { type Driver interface {
Open(name string) (Conn, error) Open(name string) (Conn, error)
} }
// src/database/sql/driver/driver.go:104-112 // [src/database/sql/driver/driver.go#L104](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/database/sql/driver/driver.go#L104)
type DriverContext interface { type DriverContext interface {
OpenConnector(name string) (Connector, error) OpenConnector(name string) (Connector, error)
} }
@@ -676,3 +676,5 @@ type Driver interface {
| Compile-time interface checks | `var _ Interface = (*Type)(nil)` | | Compile-time interface checks | `var _ Interface = (*Type)(nil)` |
| Runtime interface upgrade for optimization | `io.Copy``WriterTo`/`ReaderFrom` | | Runtime interface upgrade for optimization | `io.Copy``WriterTo`/`ReaderFrom` |
| Plugin/driver interfaces start minimal | `database/sql/driver.Driver` | | Plugin/driver interfaces start minimal | `database/sql/driver.Driver` |
<!-- PATTERN_COMPLETE -->
+13 -11
View File
@@ -6,10 +6,10 @@ Patterns extracted from the Go standard library source code.
## 1. Package-Level Documentation ## 1. Package-Level Documentation
### Source: `src/io/io.go:5-13`, `src/sync/mutex.go:5-11`, `src/context/context.go:5-57` ### Source: [src/io/io.go#L5](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L5), [src/sync/mutex.go#L5](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/mutex.go#L5), [src/context/context.go#L5](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/context/context.go#L5)
```go ```go
// src/io/io.go:5-13 // [src/io/io.go#L5](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L5)
// Package io provides basic interfaces to I/O primitives. // Package io provides basic interfaces to I/O primitives.
// Its primary job is to wrap existing implementations of such primitives, // Its primary job is to wrap existing implementations of such primitives,
// such as those in package os, into shared public interfaces that // such as those in package os, into shared public interfaces that
@@ -22,7 +22,7 @@ package io
``` ```
```go ```go
// src/sync/mutex.go:5-11 // [src/sync/mutex.go#L5](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/sync/mutex.go#L5)
// Package sync provides basic synchronization primitives such as mutual // Package sync provides basic synchronization primitives such as mutual
// exclusion locks. Other than the Once and WaitGroup types, most are intended // exclusion locks. Other than the Once and WaitGroup types, most are intended
// for use by low-level library routines. Higher-level synchronization is // for use by low-level library routines. Higher-level synchronization is
@@ -222,7 +222,7 @@ type Parser struct {
## 5. init() Functions — Use Sparingly ## 5. init() Functions — Use Sparingly
### Source: `src/net/http/http2.go:37` ### Source: [src/net/http/http2.go#L37](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/http2.go#L37)
```go ```go
// src/net/http/http2.go:37 // src/net/http/http2.go:37
@@ -379,7 +379,7 @@ srv := &http.Server{
## 7. Constructor Pattern — NewX Functions ## 7. Constructor Pattern — NewX Functions
### Source: `src/net/http/server.go:2639`, `src/database/sql/sql.go:836` ### Source: [src/net/http/server.go#L2639](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L2639), [src/database/sql/sql.go#L836](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/database/sql/sql.go#L836)
```go ```go
// src/net/http/server.go:2639 // src/net/http/server.go:2639
@@ -387,7 +387,7 @@ func NewServeMux() *ServeMux {
return new(ServeMux) return new(ServeMux)
} }
// src/database/sql/sql.go:836-843 // [src/database/sql/sql.go#L836](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/database/sql/sql.go#L836)
func OpenDB(c driver.Connector) *DB { func OpenDB(c driver.Connector) *DB {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
db := &DB{ db := &DB{
@@ -488,10 +488,10 @@ The user never sees `driver.Conn`. The driver never sees `sql.DB`'s pool logic.
## 10. Context Key Pattern — Type-Safe Context Values ## 10. Context Key Pattern — Type-Safe Context Values
### Source: `src/context/context.go:132-164`, `src/net/http/server.go:244-252` ### Source: [src/context/context.go#L132](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/context/context.go#L132), [src/net/http/server.go#L244](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L244)
```go ```go
// src/context/context.go:132-164 (from doc) // [src/context/context.go#L132](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/context/context.go#L132) (from doc)
// package user // package user
// //
// type key int // type key int
@@ -508,7 +508,7 @@ The user never sees `driver.Conn`. The driver never sees `sql.DB`'s pool logic.
``` ```
```go ```go
// src/net/http/server.go:244-252 // [src/net/http/server.go#L244](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L244)
var ( var (
ServerContextKey = &contextKey{"http-server"} ServerContextKey = &contextKey{"http-server"}
LocalAddrContextKey = &contextKey{"local-addr"} LocalAddrContextKey = &contextKey{"local-addr"}
@@ -598,10 +598,10 @@ ctx = context.WithValue(ctx, "timeout", 5*time.Second) // use function params!
## 11. Struct Tags for Codec Configuration ## 11. Struct Tags for Codec Configuration
### Source: `src/encoding/json/tags.go:17-21`, `src/encoding/json/encode.go:101-181` ### Source: [src/encoding/json/tags.go#L17](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/encoding/json/tags.go#L17), [src/encoding/json/encode.go#L101](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/encoding/json/encode.go#L101)
```go ```go
// src/encoding/json/tags.go:17-21 // [src/encoding/json/tags.go#L17](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/encoding/json/tags.go#L17)
func parseTag(tag string) (string, tagOptions) { func parseTag(tag string) (string, tagOptions) {
tag, opt, _ := strings.Cut(tag, ",") tag, opt, _ := strings.Cut(tag, ",")
return tag, tagOptions(opt) return tag, tagOptions(opt)
@@ -645,3 +645,5 @@ Struct tags are metadata for codecs. The `json` package reads `json:"..."` tags
| API layers | Separate user from implementor (SPI) | | API layers | Separate user from implementor (SPI) |
| Context values | Unexported key type + typed accessors | | Context values | Unexported key type + typed accessors |
| Configuration | Struct literals or functional options | | Configuration | Struct literals or functional options |
<!-- PATTERN_COMPLETE -->
+13 -9
View File
@@ -1,10 +1,12 @@
# Struct Design Patterns in the Go Standard Library # Struct Design Patterns in the Go Standard Library
**Source:** [golang/go](https://github.com/golang/go) at commit [`17bd5ab`](https://github.com/golang/go/tree/17bd5ab8c650155dd2bd09f7005726552639eea0)
## 1. Zero-Value Usability ## 1. Zero-Value Usability
**Pattern name:** Zero Value Ready **Pattern name:** Zero Value Ready
**Source citation:** `net/http/client.go` lines 3135, `strings/builder.go` lines 1416 **Source citation:** [net/http/client.go#L31](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/client.go#L31), [strings/builder.go#L14](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/strings/builder.go#L14)
**What it does:** Structs are designed so their zero value is immediately useful without **What it does:** Structs are designed so their zero value is immediately useful without
explicit initialization. Nil fields fall back to sensible defaults at method call time. explicit initialization. Nil fields fall back to sensible defaults at method call time.
@@ -126,7 +128,7 @@ type Buffer struct {
**Pattern name:** Indirection via Unexported Impl **Pattern name:** Indirection via Unexported Impl
**Source citation:** `os/types.go` lines 1620, `os/file_unix.go` lines 5971 **Source citation:** [os/types.go#L16](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/os/types.go#L16), [os/file_unix.go#L59](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/os/file_unix.go#L59)
**What it does:** The exported type (`File`) embeds a pointer to an unexported type **What it does:** The exported type (`File`) embeds a pointer to an unexported type
(`*file`) that holds the real implementation state. Users interact only with the (`*file`) that holds the real implementation state. Users interact only with the
@@ -173,7 +175,7 @@ type file struct {
**Pattern name:** NewXxx Constructor **Pattern name:** NewXxx Constructor
**Source citation:** `bufio/scan.go` lines 8996, `bufio/bufio.go` lines 5060 **Source citation:** [bufio/scan.go#L89](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/bufio/scan.go#L89), [bufio/bufio.go#L50](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/bufio/bufio.go#L50)
**What it does:** A package-level function `NewXxx(deps) *Xxx` constructs the type **What it does:** A package-level function `NewXxx(deps) *Xxx` constructs the type
with required dependencies and internal defaults that can't be expressed via zero with required dependencies and internal defaults that can't be expressed via zero
@@ -294,7 +296,7 @@ func NewRequest(method, url string, body io.Reader) (*Request, error) {
**Pattern name:** NewXxx / NewXxxSize Pair **Pattern name:** NewXxx / NewXxxSize Pair
**Source citation:** `bufio/bufio.go` lines 50, 62, 589, 607 **Source citation:** [bufio/bufio.go#L50](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/bufio/bufio.go#L50), 62, 589, 607
**What it does:** Provides two constructors — one with defaults (`NewReader`) and one **What it does:** Provides two constructors — one with defaults (`NewReader`) and one
with explicit configuration (`NewReaderSize`). The default version calls the with explicit configuration (`NewReaderSize`). The default version calls the
@@ -325,7 +327,7 @@ func NewWriter(w io.Writer) *Writer {
**Pattern name:** Configuration Struct (Exported Fields, Nil-Means-Default) **Pattern name:** Configuration Struct (Exported Fields, Nil-Means-Default)
**Source citation:** `net/http/server.go` lines 30203120, `crypto/tls/common.go` lines 566+, `log/slog/handler.go` lines 135175 **Source citation:** [net/http/server.go#L3020](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L3020), [crypto/tls/common.go#L566](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/crypto/tls/common.go#L566)+, [log/slog/handler.go#L135](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/log/slog/handler.go#L135)
**What it does:** A struct with exported, documented fields provides all **What it does:** A struct with exported, documented fields provides all
configuration knobs. Nil/zero values always mean "use the default". configuration knobs. Nil/zero values always mean "use the default".
@@ -440,7 +442,7 @@ func NewTextHandler(w io.Writer, opts *HandlerOptions) *TextHandler {
**Pattern name:** Interface Abstraction for Pluggable Implementations **Pattern name:** Interface Abstraction for Pluggable Implementations
**Source citation:** `crypto/crypto.go` lines 180200, `net/http/transport.go` lines 6682 **Source citation:** [crypto/crypto.go#L180](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/crypto/crypto.go#L180), [net/http/transport.go#L66](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/transport.go#L66)
**What it does:** Core behavior is defined via an interface. The package provides **What it does:** Core behavior is defined via an interface. The package provides
a default concrete implementation, but any user type satisfying the interface a default concrete implementation, but any user type satisfying the interface
@@ -485,7 +487,7 @@ type Client struct {
**Pattern name:** copyCheck (Runtime Copy Detection) **Pattern name:** copyCheck (Runtime Copy Detection)
**Source citation:** `strings/builder.go` lines 2540 **Source citation:** [strings/builder.go#L25](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/strings/builder.go#L25)
**What it does:** On first mutation, the Builder records its own address. Subsequent **What it does:** On first mutation, the Builder records its own address. Subsequent
mutations compare the current receiver address against the recorded one. If they mutations compare the current receiver address against the recorded one. If they
@@ -517,7 +519,7 @@ func (b *Builder) copyCheck() {
**Pattern name:** Package-Level Default Instance **Pattern name:** Package-Level Default Instance
**Source citation:** `net/http/client.go` line 109, `net/http/transport.go` lines 4758 **Source citation:** [net/http/client.go#L109](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/client.go#L109), [net/http/transport.go#L47](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/transport.go#L47)
**What it does:** The package provides a pre-configured, ready-to-use instance as **What it does:** The package provides a pre-configured, ready-to-use instance as
a package-level variable. Package-level convenience functions delegate to it. a package-level variable. Package-level convenience functions delegate to it.
@@ -557,7 +559,7 @@ var DefaultTransport RoundTripper = &Transport{
**Pattern name:** Post-Construction Configuration via Methods **Pattern name:** Post-Construction Configuration via Methods
**Source citation:** `bufio/scan.go` lines 275293 **Source citation:** [bufio/scan.go#L275](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/bufio/scan.go#L275)
**What it does:** After construction with `NewScanner`, optional configuration is **What it does:** After construction with `NewScanner`, optional configuration is
applied via methods (`Split`, `Buffer`) before the first call to `Scan`. applied via methods (`Split`, `Buffer`) before the first call to `Scan`.
@@ -595,3 +597,5 @@ func (s *Scanner) Split(split SplitFunc) {
s.split = split s.split = split
} }
``` ```
<!-- PATTERN_COMPLETE -->
+13 -9
View File
@@ -1,5 +1,7 @@
# Code Style Patterns in the Go Standard Library # Code Style Patterns in the Go Standard Library
**Source:** [golang/go](https://github.com/golang/go) at commit [`17bd5ab`](https://github.com/golang/go/tree/17bd5ab8c650155dd2bd09f7005726552639eea0)
## 1. Naming Conventions: mixedCaps (No Underscores) ## 1. Naming Conventions: mixedCaps (No Underscores)
**Pattern name:** mixedCaps / MixedCaps **Pattern name:** mixedCaps / MixedCaps
@@ -34,7 +36,7 @@ const shutdownPollIntervalMax = 500 * time.Millisecond
**Pattern name:** Acronym Capitalization **Pattern name:** Acronym Capitalization
**Source citation:** `net/http/request.go` line 130 (`URL`), `net/http/server.go` line 3041 (`TLSConfig`), `encoding/json/stream.go` line 280 (`JSON`) **Source citation:** [net/http/request.go#L130](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/request.go#L130) (`URL`), [net/http/server.go#L3041](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L3041) (`TLSConfig`), [encoding/json/stream.go#L280](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/encoding/json/stream.go#L280) (`JSON`)
**What it does:** Acronyms and initialisms (URL, HTTP, ID, JSON, XML, HTML, TLS, TCP) **What it does:** Acronyms and initialisms (URL, HTTP, ID, JSON, XML, HTML, TLS, TCP)
are always fully capitalized when exported, and fully lowercased when unexported. are always fully capitalized when exported, and fully lowercased when unexported.
@@ -101,7 +103,7 @@ pattern.go — URL pattern matching (ServeMux routing)
**Pattern name:** `var _ Interface = (*Type)(nil)` **Pattern name:** `var _ Interface = (*Type)(nil)`
**Source citation:** `io/io.go` line 645, `os/file.go` lines 747750, `encoding/json/stream.go` lines 280281 **Source citation:** [io/io.go#L645](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L645), [os/file.go#L747](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/os/file.go#L747), [encoding/json/stream.go#L280](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/encoding/json/stream.go#L280)
**What it does:** A package-level `var _ InterfaceName = (*ConcreteType)(nil)` declares **What it does:** A package-level `var _ InterfaceName = (*ConcreteType)(nil)` declares
that the concrete type must satisfy the interface. The compiler verifies this at that the concrete type must satisfy the interface. The compiler verifies this at
@@ -193,7 +195,7 @@ var _ Pusher = (*timeoutWriter)(nil)
**Pattern name:** Named Returns for Documentation (and Defer) **Pattern name:** Named Returns for Documentation (and Defer)
**Source citation:** `io/io.go` lines 87, 100, 314, 387; `os/file.go` lines 140, 175 **Source citation:** [io/io.go#L87](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/io/io.go#L87), 100, 314, 387; [os/file.go#L140](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/os/file.go#L140), 175
**What it does:** Return values are given names when the names add documentary value **What it does:** Return values are given names when the names add documentary value
(clarifying which int is what) or when `defer` needs to modify the return value. (clarifying which int is what) or when `defer` needs to modify the return value.
@@ -239,7 +241,7 @@ func (f *File) Read(b []byte) (n int, err error) {
**Pattern name:** `defer mu.Unlock()` / `defer f.Close()` **Pattern name:** `defer mu.Unlock()` / `defer f.Close()`
**Source citation:** `net/http/server.go` lines 31733174, `net/http/example_handle_test.go` lines 2122 **Source citation:** [net/http/server.go#L3173](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L3173), [net/http/example_handle_test.go#L21](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/example_handle_test.go#L21)
**What it does:** Resources acquired at the top of a scope are immediately deferred **What it does:** Resources acquired at the top of a scope are immediately deferred
for cleanup. Mutexes are locked then immediately `defer Unlock()`'d. for cleanup. Mutexes are locked then immediately `defer Unlock()`'d.
@@ -277,7 +279,7 @@ func (h *countHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
**Pattern name:** Sentinel Errors + Structured Error Types **Pattern name:** Sentinel Errors + Structured Error Types
**Source citation:** `os/error.go` lines 1427, `os/error.go` lines 4667 **Source citation:** [os/error.go#L14](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/os/error.go#L14), [os/error.go#L46](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/os/error.go#L46)
**What it does:** Package-level sentinel errors (`ErrNotExist`, `ErrPermission`) are **What it does:** Package-level sentinel errors (`ErrNotExist`, `ErrPermission`) are
declared as `var` for use with `errors.Is()`. Structured error types (`*PathError`, declared as `var` for use with `errors.Is()`. Structured error types (`*PathError`,
@@ -357,7 +359,7 @@ func (f *File) Name() string { ... }
**Pattern name:** Typed Constants with iota **Pattern name:** Typed Constants with iota
**Source citation:** `crypto/crypto.go` lines 7085, `time/time.go` lines 936943 **Source citation:** [crypto/crypto.go#L70](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/crypto/crypto.go#L70), [time/time.go#L936](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/time/time.go#L936)
**What it does:** Related constants are grouped in a `const ( ... )` block using **What it does:** Related constants are grouped in a `const ( ... )` block using
a named type and `iota` for sequential values. Constants of the same type a named type and `iota` for sequential values. Constants of the same type
@@ -463,7 +465,7 @@ const (
**Pattern name:** `// guards x` Field Comments **Pattern name:** `// guards x` Field Comments
**Source citation:** `net/http/example_handle_test.go` line 16 **Source citation:** [net/http/example_handle_test.go#L16](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/example_handle_test.go#L16)
**What it does:** When a sync primitive (mutex) protects specific fields, a brief **What it does:** When a sync primitive (mutex) protects specific fields, a brief
comment documents what it guards: `mu sync.Mutex // guards n`. comment documents what it guards: `mu sync.Mutex // guards n`.
@@ -490,7 +492,7 @@ type countHandler struct {
**Pattern name:** Named Type for Semantic Units **Pattern name:** Named Type for Semantic Units
**Source citation:** `time/time.go` lines 915943 **Source citation:** [time/time.go#L915](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/time/time.go#L915)
**What it does:** `Duration` is `type Duration int64` — a named type over a primitive. **What it does:** `Duration` is `type Duration int64` — a named type over a primitive.
This gives it its own method set (`String()`, `Hours()`, `Truncate()`) and prevents This gives it its own method set (`String()`, `Hours()`, `Truncate()`) and prevents
@@ -611,7 +613,7 @@ checking in code that `gofmt` would modify.
**Pattern name:** Grouped Imports (stdlib / external / internal) **Pattern name:** Grouped Imports (stdlib / external / internal)
**Source citation:** `net/http/server.go` lines 836 **Source citation:** [net/http/server.go#L8](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/server.go#L8)
**What it does:** Imports are organized in groups separated by blank lines: **What it does:** Imports are organized in groups separated by blank lines:
1. Standard library 1. Standard library
@@ -641,3 +643,5 @@ import (
"golang.org/x/net/http/httpguts" "golang.org/x/net/http/httpguts"
) )
``` ```
<!-- PATTERN_COMPLETE -->
+18 -14
View File
@@ -1,5 +1,7 @@
# Advanced Go Testing Patterns # Advanced Go Testing Patterns
**Source:** [golang/go](https://github.com/golang/go) at commit [`17bd5ab`](https://github.com/golang/go/tree/17bd5ab8c650155dd2bd09f7005726552639eea0)
Patterns extracted from the Go standard library (`src/net/http/`, `src/encoding/json/`, `src/testing/`) and Kubernetes source code. Patterns extracted from the Go standard library (`src/net/http/`, `src/encoding/json/`, `src/testing/`) and Kubernetes source code.
--- ---
@@ -10,7 +12,7 @@ The canonical Go test style. Every Go stdlib test file uses this pattern.
### Pattern Name: Anonymous Struct Test Table ### Pattern Name: Anonymous Struct Test Table
**Source:** `/tmp/go-src/src/net/http/header_test.go` lines 17-108 **Source:** [src/net/http/header_test.go#L17](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/header_test.go#L17)
**What they do:** Define test cases as a slice of anonymous structs, iterate with a range loop. **What they do:** Define test cases as a slice of anonymous structs, iterate with a range loop.
@@ -145,7 +147,7 @@ func TestHeaderWrite(t *testing.T) {
### Pattern Name: Named Table Tests with t.Run (Subtests) ### Pattern Name: Named Table Tests with t.Run (Subtests)
**Source:** `/tmp/go-src/src/encoding/json/encode_test.go` lines 285-320, `/tmp/go-src/src/encoding/json/scanner_test.go` lines 30-50 **Source:** [src/encoding/json/encode_test.go#L285](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/encoding/json/encode_test.go#L285), [src/encoding/json/scanner_test.go#L30](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/encoding/json/scanner_test.go#L30)
**What they do:** Combine table-driven tests with `t.Run` for named subtests. Use a `CaseName` struct that captures file/line for error reporting. **What they do:** Combine table-driven tests with `t.Run` for named subtests. Use a `CaseName` struct that captures file/line for error reporting.
@@ -180,7 +182,7 @@ func TestValid(t *testing.T) {
### Pattern Name: CaseName with Caller Position Tracking ### Pattern Name: CaseName with Caller Position Tracking
**Source:** `/tmp/go-src/src/encoding/json/internal/jsontest/testcase.go` lines 18-37 **Source:** [src/encoding/json/internal/jsontest/testcase.go#L18](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/encoding/json/internal/jsontest/testcase.go#L18)
**What they do:** Create a helper type that captures the caller's file:line at the point of test case declaration, so error messages point back to the exact test case definition. **What they do:** Create a helper type that captures the caller's file:line at the point of test case declaration, so error messages point back to the exact test case definition.
@@ -214,7 +216,7 @@ func (pos CasePos) String() string {
### Pattern Name: t.Helper() for Clean Stack Traces ### Pattern Name: t.Helper() for Clean Stack Traces
**Source:** `/tmp/go-src/src/testing/testing.go` lines 1415-1435 **Source:** [src/testing/testing.go#L1415](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/testing/testing.go#L1415)
**What they do:** Call `t.Helper()` as the first line in any test utility function. This marks the function as a helper, so test failure messages report the caller's line instead of the helper's line. **What they do:** Call `t.Helper()` as the first line in any test utility function. This marks the function as a helper, so test failure messages report the caller's line instead of the helper's line.
@@ -254,7 +256,7 @@ func run[T TBRun[T]](t T, f func(t T, mode testMode), opts ...any) {
### Pattern Name: *testing.T as First Argument to Helpers ### Pattern Name: *testing.T as First Argument to Helpers
**Source:** `/tmp/go-src/src/net/http/serve_test.go` lines 4555-4580 **Source:** [src/net/http/serve_test.go#L4555](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/serve_test.go#L4555)
**What they do:** Pass `*testing.T` (or `testing.TB`) as the first argument to test helper functions, making the dependency on the test context explicit. **What they do:** Pass `*testing.T` (or `testing.TB`) as the first argument to test helper functions, making the dependency on the test context explicit.
@@ -288,7 +290,7 @@ mustGet := func(url string, headers ...string) {
### Pattern Name: t.Cleanup for Test-Scoped Resources ### Pattern Name: t.Cleanup for Test-Scoped Resources
**Source:** `/tmp/go-src/src/testing/testing.go` lines 1439-1468, `/tmp/go-src/src/net/http/clientserver_test.go` lines 120-127 **Source:** [src/testing/testing.go#L1439](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/testing/testing.go#L1439), [src/net/http/clientserver_test.go#L120](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/clientserver_test.go#L120)
**What they do:** Use `t.Cleanup(fn)` instead of `defer` for resource cleanup in tests. **What they do:** Use `t.Cleanup(fn)` instead of `defer` for resource cleanup in tests.
@@ -348,7 +350,7 @@ ServeFile(w, r, "testdata/file")
### Pattern Name: Golden Files with -update Flag ### Pattern Name: Golden Files with -update Flag
**Source:** `/tmp/go-src/src/cmd/gofmt/gofmt_test.go` lines 18, 113-138 **Source:** [src/cmd/gofmt/gofmt_test.go#L18](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/cmd/gofmt/gofmt_test.go#L18), 113-138
**What they do:** Compare test output against `.golden` files. Provide a `-update` flag that regenerates golden files from current output when behavior intentionally changes. **What they do:** Compare test output against `.golden` files. Provide a `-update` flag that regenerates golden files from current output when behavior intentionally changes.
@@ -488,7 +490,7 @@ func TestRewrite(t *testing.T) {
### Pattern Name: httptest.NewRecorder for Unit-Testing Handlers ### Pattern Name: httptest.NewRecorder for Unit-Testing Handlers
**Source:** `/tmp/go-src/src/net/http/serve_test.go` lines 387-393 **Source:** [src/net/http/serve_test.go#L387](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/serve_test.go#L387)
**What they do:** Use `httptest.NewRecorder()` to test HTTP handlers without starting a server. Captures status code, headers, and body. **What they do:** Use `httptest.NewRecorder()` to test HTTP handlers without starting a server. Captures status code, headers, and body.
@@ -591,7 +593,7 @@ func TestServeMuxHandler(t *testing.T) {
### Pattern Name: httptest.NewServer for Integration-Style Tests ### Pattern Name: httptest.NewServer for Integration-Style Tests
**Source:** `/tmp/go-src/src/net/http/clientserver_test.go` lines 203-280 **Source:** [src/net/http/clientserver_test.go#L203](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/clientserver_test.go#L203)
**What they do:** Use `httptest.NewServer` / `httptest.NewUnstartedServer` for end-to-end HTTP testing with a real TCP listener on localhost. **What they do:** Use `httptest.NewServer` / `httptest.NewUnstartedServer` for end-to-end HTTP testing with a real TCP listener on localhost.
@@ -622,7 +624,7 @@ func newClientServerTest(t testing.TB, mode testMode, h Handler, opts ...any) *c
### Pattern Name: b.ReportAllocs + b.RunParallel + b.SetBytes ### Pattern Name: b.ReportAllocs + b.RunParallel + b.SetBytes
**Source:** `/tmp/go-src/src/encoding/json/bench_test.go` lines 85-101 **Source:** [src/encoding/json/bench_test.go#L85](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/encoding/json/bench_test.go#L85)
**What they do:** Combine `b.ReportAllocs()` for allocation reporting, `b.RunParallel` for concurrent benchmarks, and `b.SetBytes` for throughput metrics. **What they do:** Combine `b.ReportAllocs()` for allocation reporting, `b.RunParallel` for concurrent benchmarks, and `b.SetBytes` for throughput metrics.
@@ -660,7 +662,7 @@ func BenchmarkCodeEncoder(b *testing.B) {
### Pattern Name: testing.Short() for Expensive Tests ### Pattern Name: testing.Short() for Expensive Tests
**Source:** `/tmp/go-src/src/net/http/serve_test.go` lines 800, 1000, 2212, 2581 **Source:** [src/net/http/serve_test.go#L800](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/serve_test.go#L800), 1000, 2212, 2581
**What they do:** Skip slow/flaky/network-dependent tests with `testing.Short()`. The Go CI runs with `-short` in fast mode, full tests in thorough mode. **What they do:** Skip slow/flaky/network-dependent tests with `testing.Short()`. The Go CI runs with `-short` in fast mode, full tests in thorough mode.
@@ -754,7 +756,7 @@ func afterTest(t testing.TB) {
### Pattern Name: Bridge File for Internal Testing ### Pattern Name: Bridge File for Internal Testing
**Source:** `/tmp/go-src/src/net/http/export_test.go` lines 1-50 **Source:** [src/net/http/export_test.go#L1](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/export_test.go#L1)
**What they do:** Create an `export_test.go` file in the package itself (package `http`, not `http_test`) that exports internal symbols to external test packages. Only compiled during testing. **What they do:** Create an `export_test.go` file in the package itself (package `http`, not `http_test`) that exports internal symbols to external test packages. Only compiled during testing.
@@ -779,7 +781,7 @@ var (
### Pattern Name: Generic Test Runner Across Protocol Modes ### Pattern Name: Generic Test Runner Across Protocol Modes
**Source:** `/tmp/go-src/src/net/http/clientserver_test.go` lines 100-134 **Source:** [src/net/http/clientserver_test.go#L100](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/clientserver_test.go#L100)
**What they do:** A generic `run[T]` function that executes every client/server test in HTTP/1.1, HTTP/2, and HTTP/3 modes automatically. Tests opt into specific modes via options. **What they do:** A generic `run[T]` function that executes every client/server test in HTTP/1.1, HTTP/2, and HTTP/3 modes automatically. Tests opt into specific modes via options.
@@ -810,7 +812,7 @@ func run[T TBRun[T]](t T, f func(t T, mode testMode), opts ...any) {
### Pattern Name: io.Writer Adapter for *testing.T ### Pattern Name: io.Writer Adapter for *testing.T
**Source:** `/tmp/go-src/src/net/http/clientserver_test.go` lines 337-345 **Source:** [src/net/http/clientserver_test.go#L337](https://github.com/golang/go/blob/17bd5ab8c650155dd2bd09f7005726552639eea0/src/net/http/clientserver_test.go#L337)
**What they do:** Implement `io.Writer` backed by `t.Logf`, so server error logs appear in test output (visible with `-v`, suppressed otherwise). **What they do:** Implement `io.Writer` backed by `t.Logf`, so server error logs appear in test output (visible with `-v`, suppressed otherwise).
@@ -830,3 +832,5 @@ func (w testLogWriter) Write(b []byte) (int, error) {
// Usage: // Usage:
cst.ts.Config.ErrorLog = log.New(testLogWriter{t}, "", 0) cst.ts.Config.ErrorLog = log.New(testLogWriter{t}, "", 0)
``` ```
<!-- PATTERN_COMPLETE -->