Go Syntax Decoder

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.

The function header — reading order

func (s *Service) GetAsset(ctx context.Context, id string) (*models.Asset, error) {
① receiver = the "self"; *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).

Tokens with no Python analog

GoReads asPython
name typetype comes after the namename: type
*Tpointer to T (may be nil)
&xaddress of x
*p (expr)value at p (deref)
[]Tslice of T (growable list)list[T]
[n]Tarray of T, fixed length n
map[K]Vmap K → Vdict[K,V]
chan Tchannel of T~asyncio.Queue
<-chreceive from chawait q.get()
ch<-vsend v to chq.put(v)
func()a function value/typecallable
...Tvariadic (zero+ args)*args
iface.(T)type assertionisinstance-ish

:= vs = (the biggest trap)

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.

Comma-ok forms

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.

Declaration shapes you'll meet

// 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()

Receivers: pointer vs value (L4)

UseWhenSatisfies interface as
(s *T) pointermutates receiver · large struct · has Mutex/no-copy field · default when unsureonly *T
(s T) valuesmall, 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.

Zero values — what an uninitialized var holds

TypeZeroTypeZero
numbers0pointernil
string""slice / mapnil
boolfalseinterface / chan / funcnil

No "undefined". A declared-but-unset var is always its zero value. nil map reads OK but writes panic.

Concurrency: channels & the leak smell (L6)

OpBehavior
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 sendpanic — sender closes, after all sends done
send on nil chanblocks forever
for v := range chdrains 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.

Reviewer's quick-flag list