Read any Go line at a glance. Built for the second monitor while reviewing PRs.
Sources: Go spec · Effective Go · Code Review Comments. Lesson: 03.
⌘P to print — laid out for one sheet.*Service = method on pointer
② params: name type, ctx first
③ returns: value(s) + error, error last
Scan order: receiver → name → params → returns. Capital first letter ⇒ exported (public).
| Go | Reads as | Python |
|---|---|---|
name type | type comes after the name | name: type |
*T | pointer to T (may be nil) | — |
&x | address of x | — |
*p (expr) | value at p (deref) | — |
[]T | slice of T (growable list) | list[T] |
[n]T | array of T, fixed length n | — |
map[K]V | map K → V | dict[K,V] |
chan T | channel of T | ~asyncio.Queue |
<-ch | receive from ch | await q.get() |
ch<-v | send v to ch | q.put(v) |
func() | a function value/type | callable |
...T | variadic (zero+ args) | *args |
iface.(T) | type assertion | isinstance-ish |
x := v // NEW var, type inferred
x = v // assign to EXISTING var
a, err := f() // both new
a, err = g() // both existing
b, err := h() // b new, err reused (ok:
// := allows mix if ≥1 is new)
Shadowing risk: := in an inner block makes a fresh local that hides the outer var. Common bug — flag it.
v, ok := m[k] // map: ok=found?
v, ok := x.(T) // type assert: ok=is T?
v, ok := <-ch // recv: ok=channel open?
Missing map key → zero value, ok=false. No panic, no error.
// struct + tags
type Config struct {
BatchSize int `validate:"required"`
}
// field type `tag` (reflection metadata)
// interface = method set
type Client interface {
ListDApps(ctx context.Context) ([]*DApp, error)
}
// constructor: (value, cleanup, error) triple
func NewService(c *Config) (*Service, func(), error)
// const block with iota (auto-increment)
const (
A = iota // 0
B // 1
C // 2
)
// defer: run at function exit (cleanup)
defer conn.Close()
| Use | When | Satisfies interface as |
|---|---|---|
(s *T) pointer | mutates receiver · large struct · has Mutex/no-copy field · default when unsure | only *T |
(s T) value | small, immutable, read-only (e.g. Address, Tier) | both T and *T |
Copy bug: value receiver assigning to a field → mutation lost, no error. Iface error: "method has pointer receiver" → pass &T{} not T{}. Never mix receiver kinds on one type.
| Type | Zero | Type | Zero |
|---|---|---|---|
| numbers | 0 | pointer | nil |
| string | "" | slice / map | nil |
| bool | false | interface / chan / func | nil |
No "undefined". A declared-but-unset var is always its zero value. nil map reads OK but writes panic.
| Op | Behavior |
|---|---|
go f() | launch concurrent, returns now (no await) |
make(chan T) | unbuffered: send blocks till receive |
make(chan T, n) | buffered: send blocks only when full |
close(ch) then send | panic — sender closes, after all sends done |
send on nil chan | blocks forever |
for v := range ch | drains till closed (no close → blocks forever) |
For every go: (1) how does it stop? (2) who reads its sends, can they vanish early? (3) is shared state synced? Can't answer all 3 from the diff → leave a comment. Suspect races → go test -race.
_ or unchecked → comment.:= shadowing an outer variable inside a block → likely bug., ok then used → may hide a zero-value bug.ctx not the first param, or stored in a struct → convention break.Url/Id/Http → initialisms stay all-caps: URL, ID, HTTP.%v wrapping an error the caller later errors.Is → breaks the chain; use %w.go with no stop path → goroutine leak. close before Wait → panic.