← Files GophersARCHIVED FILE

skills/go-naming/references/identifiers-and-scope.md

3.99 KB · Oct 3, 2026 · 06:31 UTC

↓ Download file

# Identifiers, Scope, Acronyms, and Aliases

The point of Go's naming rules is to keep the reader's eyes on the meaning, not on the letters. Length, casing, and consistency exist to serve that.

## Scope-Based Length

Length should be proportional to how far the reader has to look to understand a name.

| Scope | Length | Examples |
|---|---|---|
| 1-7 line block | Single letter | `i`, `r`, `w`, `b`, `n`, `v` |
| Single function | Short word | `count`, `buf`, `items`, `users` |
| Package-level | Descriptive | `defaultTimeout`, `parseHTTPHeader` |
| Exported API | Full noun/verb phrase | `MaxIdleConnsPerHost`, `NewRequestWithContext` |

Common conventional single letters:

- `i`, `j`, `k` — loop indices
- `r`, `w` — `io.Reader`, `io.Writer`
- `b` — byte slice / buffer
- `n` — count
- `v` — value (range value)
- `s` — string / `Server` receiver
- `c`, `ch` — channel
- `m` — map

## Receivers

Receivers are method-local: every call site shows the type already. A one- or two-letter abbreviation of the type is enough.

```go
func (s *Server) Start()    // not (server *Server)
func (b *Buffer) Write(...) // not (this *Buffer)
func (q *Queue) Push(v T)   // consistent across all methods of Queue
```

Rules:

- **Consistent across all methods of the type.** Switching between `s`, `srv`, `server` is noise.
- **Never `this` or `self`.** Those come from other languages.
- **Same letter across families** is fine: most stdlib `*Request`/`*Response` receivers use `r`/`w` depending on context.

If your receiver name has to be descriptive ("server", "buffer") to make sense, the method is probably too long.

## Initialisms and Acronyms

Initialisms keep one case across the whole word. The rule is: pick all-upper for exported, all-lower for unexported, but never mix within one initialism.

```go
// Good
URL           // exported, all caps
userID        // unexported boundary: user(lower) + ID(upper)
HTTPServer    // exported
xmlParser     // unexported start, all-lower
ParseURL      // exported verb
```

```go
// Wrong — mixed case within one initialism
Url           // U + rl
HttpServer    // H + ttp
ParseUrl      // U + rl
xmlAPI        // ambiguous: xml + API? xmlA + PI?
```

Multiple initialisms in one name: still uniform per initialism (`HTTPSAPI`, `xmlAPI`).

## Variable Naming Pitfalls

- **No type in the name.** `users` not `userSlice`, `name` not `nameStr`. The type is right there.
- **No Hungarian.** `iCount` is wrong; `count` is fine.
- **Don't shadow loop variables.** Each `for i := range ...` introduces a fresh `i`; reusing the name across scopes makes diffs confusing.
- **Prefix unexported package globals** with `_` only when you specifically need to prevent shadowing in nested scopes — most projects do not need this.

## Import Aliases

Only alias on collision or when the package name is unhelpfully generic. Otherwise the alias is cognitive load: readers cannot grep for the alias.

```go
import (
    "math/rand"
    mrand "math/rand/v2"          // good: disambiguates
    pb "example.com/api/v1/userpb" // good: short alias for generated code
)
```

Avoid:

```go
import h "net/http" // bad: hides the well-known package name
import . "fmt"      // bad: dot import, pollutes namespace
```

`_ "image/png"` (blank import) is fine when you need the side effect (`init` registration) — but keep blank imports in `main` or test packages where the side effect is visible.

## File Names

- Lowercase, underscores OK: `user_handler.go`, `order_test.go`.
- Test files end in `_test.go`.
- Build-tag files: `foo_linux.go`, `foo_amd64.go` — the suffix matches the build tag.
- One primary type per file when the type has many methods.

## Anti-Patterns

- Long names in short loops: `for userIndex := range users` — use `i`.
- Inconsistent receiver names: `(s *Server)` in one method, `(srv *Server)` in another.
- `userId`, `httpUrl`, `xmlApi` — initialism case mixing.
- Aliasing without collision: `import h "net/http"`.
- `_ "github.com/lib/pq"` deep inside a library package — side effects hidden from callers.

SHA-256: 492162caf02d8a146f9f7c4a356e01f3c092047d8933dc78e379ed50948110e8