Chapter 9: Naming Rules
Go Variable Naming Rules & Conventions — this is where Go feels very different from Java/Python/C#.
Go has two layers:
- Strict syntax rules (from the language spec — what compiles, what doesn’t)
- Strong idiomatic conventions (from Effective Go, standard library, community — what makes code feel “Go-like”)
I’ll explain both like your patient teacher, with tables, examples, why each rule exists, and common mistakes.
1. Strict Syntax Rules (Compiler Enforced — Must Follow or It Won’t Compile)
From the official Go spec (https://go.dev/ref/spec#Identifiers — still unchanged in Go 1.26):
- An identifier (variable name, function name, type name, etc.) is:
- One or more letters + unicode digits
- First character must be a letter (includes Unicode letters like హ from Telugu!)
- Subsequent characters: letters, unicode digits (0-9), or underscore _
- Cannot be a keyword (if, for, var, func, package, import, etc.)
- Case-sensitive (Age ≠ age)
- No spaces, no hyphens, no special chars like @ # $ % ^ & * (except underscore)
Valid examples:
|
0 1 2 3 4 5 6 7 8 9 10 |
userName // ok user_name // ok (but rarely used — see conventions) హైదరాబాద్User // ok! Unicode letters allowed (but please don't abuse this) maxRetries // ok _ignored // ok (blank identifier special case) |
Invalid examples (won’t compile):
|
0 1 2 3 4 5 6 7 8 9 |
2ndPlace // starts with digit — error user-name // hyphen not allowed user@name // @ invalid var // keyword |
Blank identifier _ — special case:
- You can use _ as a name when you want to ignore a value (especially in multiple returns)
- But you cannot read from _ (it’s write-only)
|
0 1 2 3 4 5 6 |
_, err := os.Open("file.txt") // ignore bytes written, keep error |
2. Idiomatic Naming Conventions (Not Enforced — But Everyone Follows Them)
These come mostly from Effective Go — read this page once, it’s gold.
Key principles:
- Use MixedCaps or mixedCaps (camelCase) — NO underscores for multi-word names
- Short is better than long — especially for local variables
- The closer the name is to its declaration → the shorter it can be
- Exported (public) names start with Uppercase
- Unexported (private/package-only) start with lowercase
- Be descriptive enough — but prefer brevity
Official advice quotes (paraphrased from Effective Go):
“Finally, the convention in Go is to use MixedCaps or mixedCaps rather than underscores to write multiword names.”
“Variable names in Go should be short rather than long. This is especially true for local variables with limited scope. Prefer c to lineCount.”
“The further from its declaration that a name is used, the more descriptive the name must be.”
Quick Style Table for Variables
| Scope / Visibility | Starting Letter | Style Example | Recommended Length | Common Names / Patterns |
|---|---|---|---|---|
| Local (inside function) | lowercase | i, n, err, user, db | Very short (1–4 chars) | i, j, k (loops), err, ctx, ok, v |
| Package-level unexported | lowercase | defaultTimeout, helperFunc | Short–medium | mu (mutex), once |
| Exported (public) | Uppercase | UserID, MaxRetries, HTTPClient | Medium–descriptive | Config, Logger, DB |
| Constants | Uppercase if exported | StatusOK, pi (unexported) | Short–medium | MaxSize, DefaultPort |
Real Examples (Good vs Avoid)
Good idiomatic code:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
func processUsers(users []User) error { for i, u := range users { // i short (loop index), u short (local) if u.Age < 18 { continue } var err error err = db.Save(u) // err very common short name if err != nil { return fmt.Errorf("save user %d: %w", i, err) } } return nil } var defaultTimeout = 30 * time.Second // unexported, descriptive but concise type Server struct { Logger *log.Logger // exported field → Uppercase mu sync.Mutex // unexported mutex → short "mu" } |
Avoid (non-idiomatic):
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
var NumberOfTimesTheUserHasLoggedInThisSession int // too long, use count or logins func Process_The_User_Information(user_information UserInformation) { // underscores bad // ... } var USER_AGE_LIMIT = 18 // ALL_CAPS usually only for constants in other languages — avoid in Go |
Special Common Short Names (You’ll See Everywhere)
| Name | Meaning / Use Case | Why Short? |
|---|---|---|
| i, j, k | Loop indices | Classic math/CS tradition |
| n | Count / length / size | Very common |
| err | Last error returned from call | Universal pattern |
| ok | Boolean from map lookup / type assertion | value, ok := m[key] |
| ctx | Context.Context (cancellation, deadlines) | Standard in modern Go |
| r | http.ResponseWriter or io.Reader | Short for reader/writer |
| w | http.ResponseWriter | Very common in HTTP handlers |
| mu | sync.Mutex | Conventional abbreviation |
| c | Client, Config, Channel, etc. | Context-dependent |
Your Mini Practice Task
Try rewriting this non-idiomatic code to proper Go style:
|
0 1 2 3 4 5 6 7 8 9 10 11 |
var The_Maximum_Number_Of_Allowed_Connections_In_The_System int = 100 func Handle_The_Incoming_Request(The_Request *http.Request) { var The_Error_From_Database error // ... } |
Idiomatic version:
|
0 1 2 3 4 5 6 7 8 9 10 11 |
const maxConnections = 100 // or var if it changes func handleRequest(r *http.Request) { var err error // ... } |
Any part unclear?
- Exported vs unexported in detail?
- Why no underscores — historical reason?
- Naming for structs/fields/methods/receivers?
- Or ready for pointers, slices, or functions next?
Keep going — you’re writing more and more “Go-like” code every day! 💪🇮🇳 Type some code with these rules and feel the difference. 🚀
