跪拜 Guibai
← All articles
Backend · Go

Go's Type System in One Sitting: Strings, Slices, Maps, and Implicit Interfaces

By 小满zs ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Go's type system is deliberately small, but the zero-value semantics, array-vs-slice distinction, and implicit interfaces are the three concepts that cause the most bugs and design friction for developers coming from Java, Python, or JavaScript. Getting them right early prevents entire categories of nil-pointer and copying mistakes.

Summary

Go's variable system starts with the full `var name type = value` declaration but quickly collapses into shorthand with type inference and the `:=` operator, which works only inside functions. Uninitialized variables don't stay null; they take a zero value — empty strings, 0 for ints, false for bools — a design choice that eliminates a class of nil-reference bugs before they start.

Arrays are fixed-length value types that copy on assignment, while slices are dynamic reference types backed by an array. The distinction matters for performance and mutation: passing an array copies the whole thing, but a slice shares the underlying data. Maps provide key-value lookups with a built-in comma-ok idiom for checking existence, sidestepping the zero-value ambiguity that plagues other languages.

Structs group fields into custom types, and interfaces tie everything together through implicit satisfaction — any type that implements the required methods automatically fulfills the contract without an `implements` keyword. This is Go's entire polymorphism story, and it's simpler than class hierarchies but demands a different mental model.

Takeaways
Variables declared without an initial value receive a zero value — empty string, 0, false, nil — not a null or undefined.
Type inference with `:=` works only inside function bodies; package-level variables require the full `var` keyword.
Arrays have fixed length and are passed by value, copying the entire array on assignment or function calls.
Slices are dynamic, reference the same underlying array, and grow via `append`; `len` reports current length while `cap` reports total capacity.
Maps use the `value, ok := map[key]` idiom to distinguish between a missing key and a key whose value happens to be the zero value.
Structs group named fields of different types and are accessed with dot notation; they form the basis of custom types in Go.
Interfaces are satisfied implicitly — any type with the right methods automatically implements the interface without explicit declaration.
The empty interface `interface{}` (or `any`) accepts any value, serving as Go's escape hatch for generic programming before generics arrived.
Conclusions

Zero values are Go's most underrated safety feature: they eliminate the billion-dollar null-reference mistake by making every type default to something useful rather than nothing.

The array-vs-slice distinction is where most newcomers leak memory or accidentally copy large data structures; slices are the default, and arrays exist mainly for low-level control.

Implicit interface satisfaction flips the dependency direction — packages define the interfaces they need, and implementations don't need to know about them, which keeps import graphs clean.

Go's type system is small enough to learn in an afternoon but subtle enough that the comma-ok map lookup and slice capacity behavior still surprise experienced developers in code review.

Concepts & terms
Zero value
The default value a Go variable holds when declared without initialization: 0 for numbers, "" for strings, false for bools, nil for pointers, slices, maps, channels, and interfaces.
Type inference
Go's compiler deduces a variable's type from its initializer, allowing `var name = "hello"` or `name := "hello"` without explicitly writing `string`.
Slice vs array
An array (`[5]int`) has a fixed length and is a value type copied on assignment. A slice (`[]int`) is a dynamic view into an array, passed by reference, and grown with `append`.
Comma-ok idiom
A Go pattern for safe map lookups: `value, ok := map[key]` where `ok` is `true` if the key exists, avoiding confusion between missing keys and zero-value entries.
Implicit interface satisfaction
A type automatically implements an interface by defining all its methods; no `implements` keyword is needed, enabling decoupled, post-hoc abstraction.
From the discussion

A brief exchange questions whether Go has an "automatic inheritance" problem, with a reply pushing back that Go lacks inheritance entirely. The third comment is just a reaction to the author learning Go.

Go's structural embedding is sometimes perceived as "automatic inheritance," which one commenter finds objectionable.
The counterpoint asserts that Go does not have inheritance at all, challenging the framing of the original complaint.
See top comments, translated →
Source: juejin.cn ↗ Google Translate ↗ Backup ↗