← [ BACK_TO_NOTES ]

Go Proverbs(Go 谚语)

Rob Pike 在《Go Proverbs》演讲中总结的 Go 设计原则全集,逐条中英对照释义,并链接到对应的原子概念笔记。

#synthesis #growing #dev #go

[!info] Related notes

Go Proverbs(Go 谚语)

[!abstract] 这是什么 《Go Proverbs》是 Rob Pike 在 2015 年 Gopherfest SV 演讲中,把 Go 长期积累的设计直觉压成的一组短句。它们不是语言规范,而是「经验法则」:告诉你 Go 偏向哪种写法、为什么不鼓励另一种。本笔记逐条给出英文原句、中文释义,并指向对应的原子概念笔记,便于从「口号」回到「机制」。

2026-10-07 已核对演讲站点所列的 19 条原句。各小节标题是原句,EN/中文段落是本笔记的释义,不是 Rob Pike 的逐字讲稿。

读这些谚语时记住一件事:它们是方向,不是禁令。例如「通过通信共享内存」并不禁止你用 sync.Mutex;它只是把 channel 设为并发的默认叙事。

目录

  • 并发与通信
    • [[#Don’t communicate by sharing memory, share memory by communicating.]]
    • [[#Concurrency is not parallelism.]]
    • [[#Channels orchestrate; mutexes serialize.]]
  • 接口与抽象
    • [[#The bigger the interface, the weaker the abstraction.]]
    • [[#Make the zero value useful.]]
    • [[#interface{} says nothing.]]
  • 工具链与依赖
    • [[#Gofmt’s style is no one’s favorite, yet gofmt is everyone’s favorite.]]
    • [[#A little copying is better than a little dependency.]]
  • 边界代码
    • [[#Syscall must always be guarded with build tags.]]
    • [[#Cgo must always be guarded with build tags.]]
    • [[#Cgo is not Go.]]
    • [[#With the unsafe package there are no guarantees.]]
  • 清晰与表达
    • [[#Clear is better than clever.]]
    • [[#Reflection is never clear.]]
  • 错误与工程
    • [[#Errors are values.]]
    • [[#Don’t just check errors, handle them gracefully.]]
    • [[#Design the architecture, name the components, document the details.]]
    • [[#Documentation is for users.]]
    • [[#Don’t panic.]]

并发与通信

Don’t communicate by sharing memory, share memory by communicating.

不要通过共享内存来通信,而要通过通信来共享内存。

EN Use channels to express a deliberate hand-off of data between goroutines. Sending a pointer, slice, or map copies the value and may leave shared references; Go does not enforce ownership transfer. The sender must follow an application-level rule to stop using handed-off mutable data, or access must still be synchronized.

中文 用 channel 表达数据的交接,可以让并发职责更清楚。但发送指针、slice 或 map 仍是值复制,双方可能保留共享引用;Go 不会像借用检查器一样强制转移所有权。发送方停止使用已交接的可变数据,是程序必须维护的协议,否则仍需同步。

关联 go-channels · go-goroutines · go-sync-package

Concurrency is not parallelism.

并发不是并行。

EN Concurrency is about structure: composing a program out of independently progressing units. Parallelism is about execution: running multiple things at the same instant on multiple CPUs. You can have concurrency without parallelism (a single core interleaving tasks); parallelism is what concurrency may achieve when there are enough processors.

中文 并发关乎结构:把一个程序组织成可独立推进的单元。并行关乎执行:在多个 CPU 上于同一瞬间同时跑多件事。可以只有并发而没有并行(单核交替推进任务);并行是并发在「处理器足够多」时才可能达到的效果。混淆二者会导致错误的扩展预期——加了核不代表并发代码自动变快。

关联 go-goroutines · 调度器与 GMP

Channels orchestrate; mutexes serialize.

channel 负责编排,mutex 负责串行化。

EN Use channels to arrange the flow of work and the hand-off of ownership between goroutines — they express intent and coordination. Use mutexes when you must protect shared state by letting only one goroutine touch it at a time — they express restriction and mutual exclusion (serialization). Pick the tool by what you mean: orchestration vs. protection.

中文 用 channel 来编排 goroutine 之间的工作流与所有权交接——它表达的是意图与协作。当你必须保护共享状态、同一时刻只允许一个 goroutine 访问时,用 mutex——它表达的是限制与互斥(串行化)。按你「想表达什么」选工具:是协作编排,还是状态保护。

关联 go-channels · go-sync-package · select


接口与抽象

The bigger the interface, the weaker the abstraction.

接口越大,抽象越弱。

EN A small interface (e.g. io.Reader with a single Read method) is easier to implement, easier to compose, and more widely reusable. A giant interface forces every implementer to satisfy many methods, which dilutes the abstraction’s power — fewer real types qualify and consumers may be coupled to unrelated capabilities. More methods do not literally mean less contract information. Go favors small interfaces defined by the consumer.

中文 小接口(如只有一个 Read 方法的 io.Reader)更易实现、更易组合、更易被广泛复用。庞大的接口强迫每个实现者满足大量方法,反而稀释了抽象的威力——真正符合的类型变少,消费者还可能耦合无关能力;并不是方法越多,契约包含的信息就越少。Go 偏好在消费方定义小接口。

关联 go-interfaces · go-compositional-interfaces · go-io-reader-writer

Make the zero value useful.

让零值有用。

EN A type’s zero value (e.g. 0, "", or the zero struct) should be usable without extra initialization. Examples: a sync.Mutex’s zero value is already ready to lock; a bytes.Buffer’s zero value is an empty, usable buffer; nil slices and nil maps can both be ranged over; a nil slice can be appended to, while inserting into a nil map panics. Design types so their zero value is a valid, ready state.

中文 类型的零值(如 0、空字符串,或零值结构体)应当无需额外初始化即可使用。例如:sync.Mutex 的零值已可直接加锁;bytes.Buffer 的零值是一个空的、可用的缓冲区;nil slice 和 nil map 都可安全 range;nil slice 可 append,nil map 写入条目会 panic,map 本身不支持 append。设计类型时应让零值处于合法、就绪状态。

关联 go-variables-constants-and-zero-values · go-sync-package · go-slices

interface{} says nothing.

interface{} 什么也说不出来。

EN The empty interface interface{} (any is an alias) requires no methods and gives callers no domain-specific static capability. An interface value still retains its dynamic type and value. Code can pass it through unchanged; when it needs specific capabilities, use checked assertions, type switches, reflection, or a more precise API.

中文 空接口 interface{}(any 是别名)不要求任何方法,因而不向调用方提供具体的静态能力契约;接口值仍保留动态类型和值。仅传递该值无需类型断言;需要特定能力时,应使用检查过的断言、type switch、反射或更准确的 API。

关联 go-interfaces · go-generics · 类型断言与 type switch


工具链与依赖

Gofmt’s style is no one’s favorite, yet gofmt is everyone’s favorite.

gofmt 的格式谁都不完全喜欢,但 gofmt 谁都喜欢。

EN Nobody loves every formatting decision gofmt makes, but everyone loves that gofmt ends style debates. Uniform formatting makes diffs, code generation, and team collaboration stable and uncontroversial. It is infrastructure, not aesthetics.

中文 没人钟爱 gofmt 做出的每一个格式化决定,但人人都爱它终结了格式之争。统一的格式让 diff、代码生成与团队协作变得稳定且无争议。它是协作基础设施,不是审美插件。

关联 go-origin-and-philosophy · 静态分析

A little copying is better than a little dependency.

一点点复制,好过一点点依赖。

EN Rather than pull in a dependency (with its maintenance, versioning, and supply-chain cost) for a small need, prefer duplicating a small amount of simple code. Copying can remove a dependency, but you then own bug fixes and updates and must respect the source license; this is not a blanket recommendation to copy complex or security-sensitive code.

中文 与其为了一点小需求就引入一个依赖(带来维护、版本与供应链成本),不如复制一小段简单代码。复制可减少外部耦合,同时也让自己承担缺陷修复、更新和许可证义务;不能据此复制复杂或安全敏感的实现。

关联 go-modules · 手动依赖注入


边界代码

Syscall must always be guarded with build tags.

系统调用必须始终用 build tag 守护。

EN Code that calls OS syscalls is platform-specific. Use build constraints, including _GOOS_GOARCH.go filename suffixes or //go:build, to select the intended platform. Unsupported targets still need an alternative implementation or an explicit unsupported boundary.

中文 调用操作系统 syscall 的代码是平台相关的。可通过 _GOOS_GOARCH.go 文件名后缀或 //go:build 限定平台,并为其他目标提供替代实现或明确不支持;不是每个文件都必须再写一条显式 tag。

关联 go-build-and-deploy · go-modules

Cgo must always be guarded with build tags.

cgo 必须始终用 build tag 守护。

EN Cgo bridges to C; it is expensive and platform-specific. Files importing “C” already imply the cgo build constraint. Additional OS/arch constraints may be needed. A pure-Go build also needs a suitable fallback; a build tag alone cannot create one.

中文 cgo 桥接 C,代价高且平台相关。导入 “C” 的文件已隐含 cgo 构建约束,必要时另加 OS/架构限制。要支持 CGO_ENABLED=0,还需要可用的替代实现;只有 tag 并不会自动获得纯 Go 版本。

关联 go-cgo

Cgo is not Go.

cgo 不是 Go。

EN Cgo code crosses the language boundary: it adds C toolchain and ABI requirements, extra pointer/lifetime rules, and cross-compilation work. Correct cgo code obeys Go GC rules rather than inherently breaking them. Treat it as a foreign dependency, not as idiomatic Go, and keep it behind a small, well-fenced surface.

中文 cgo 代码跨越了语言边界:它引入 C 工具链/ABI、额外指针生命周期规则与交叉编译成本;合法 cgo 必须遵守 GC 规则,并不是天然“破坏 GC 假设”。应把它当作外来依赖,而非惯用 Go,并用小而设防良好的边界把它圈起来。

关联 go-cgo

With the unsafe package there are no guarantees.

使用 unsafe 包就没有任何保证。

EN The unsafe package escapes Go’s type and memory safety. The package documents valid patterns, but programs importing it may be non-portable and are outside the Go 1 compatibility guarantee. Violating those patterns can corrupt memory or crash. Reach for it only when absolutely necessary, and fence it tightly.

中文 unsafe 包绕过了 Go 的类型与内存安全。包文档仍定义合法使用模式,但导入它的程序可能不可移植,且不受 Go 1 兼容性承诺保护。违反模式可能破坏内存或崩溃。除非绝对必要,否则不要用;若用,必须严密封装。

关联 go-unsafe


清晰与表达

Clear is better than clever.

清晰优于巧妙。

EN Prefer code that is obviously correct and readable over code that is terse or “smart.” Clever code is harder to maintain, review, and debug — and the cleverness rarely pays for itself.

中文 优先选择明显正确、易读的代码,而不是简短或「聪明」的代码。巧妙的代码更难维护、审查和调试——那份「巧妙」很少能抵偿它的代价。

关联 go-origin-and-philosophy

Reflection is never clear.

反射永远不清晰。

EN Reflection (reflect package) inspects types at runtime. It moves some checks to runtime and can make control flow harder to follow. It may add overhead, but performance depends on the actual path and should be measured. Keep reflection localized when it is the clearest way to implement a dynamic boundary.

中文 反射(reflect 包)在运行时检查类型。它把部分检查推迟到运行时,可能增加阅读与运行成本;性能仍需测量,不能由“用了反射”直接下结论。动态边界确实需要它时,保持使用范围清楚,并遵守有效值、可设置性等规则。

关联 go-reflection · go-type-assertions-and-type-switch


错误与工程

Errors are values.

错误即值。

EN In Go, errors are ordinary values of type error, returned from functions — not thrown exceptions. You handle them with normal control flow (if err != nil), which makes failure paths explicit, composable, and easy to thread through a call stack.

中文 在 Go 中,错误是 error 类型的普通值,由函数返回——而非抛出的异常。你用普通控制流(if err != nil)处理它们,这令失败路径显式、可组合,也易于在函数调用链中传递。

关联 go-error-handling · go-error-wrapping · go-defer-panic-and-recover

Don’t just check errors, handle them gracefully.

不要只检查错误,要优雅地处理。

EN Writing if err != nil is necessary but not sufficient. Graceful handling means adding context (wrap), returning, or recovering meaningfully — so the program degrades informatively rather than silently ignoring the failure or crashing with an opaque stack.

中文 写 if err != nil 是必要但不充分的条件。优雅处理意味着补充上下文(包装)、返回或妥善恢复——让程序以可理解的方式降级,而不是静默忽略失败,或带着一团看不懂的堆栈崩溃。

关联 go-error-handling · go-error-wrapping

Design the architecture, name the components, document the details.

设计架构,命名组件,记录细节。

EN Deliberately plan the system’s structure and component boundaries. Give components clear names that reveal intent. Write documentation for the details others need. Architecture and naming are communication — they tell readers how the pieces fit before they read a line of implementation.

中文 刻意规划系统的结构与组件边界。给组件起能揭示意图的清晰名字。为别人需要的细节写下文档。架构与命名本身就是沟通——在读者读一行实现之前,就告诉了他们各个部件如何拼合。

关联 项目布局与分层 · 程序结构

Documentation is for users.

文档是写给用户的。

EN Write docs from the reader’s perspective — what they need to use your package — not as an internal narrative of how you built it. Good documentation serves the consumer of the API.

中文 从读者的视角写文档——他们需要什么来使用你的包——而不是当作「你是怎么造出来的」内部叙事。好的文档服务于 API 的消费者。

关联 go-origin-and-philosophy

Don’t panic.

不要 panic。

EN For ordinary expected failures, return an error. Panic may represent violated invariants or a documented Must-style API; it can be recovered at an appropriate boundary and is not synonymous with an unrecoverable process error. panic aborts the normal control flow and is hard to reason about; library code should rarely, if ever, panic.

中文 普通可预期失败应返回 error;panic 可用于不变量破坏或明确约定的 Must 风格 API,也可在合适边界 recover,并不等于进程必然无法恢复。panic 会中断正常控制流、难以推理;库代码尤其不应随意 panic。

关联 go-defer-panic-and-recover · go-error-handling


本节总结

  • 这 19 条谚语是 Go 设计直觉的压缩版,不是规范;它们是方向,不是禁令。
  • 它们围绕几条主线:并发默认用通信、接口要小、零值要可用、清晰优于巧妙、错误即值、边界代码(syscall/cgo/unsafe)要设防。
  • 从「口号」回到「机制」:每条都链接到对应的原子概念笔记(见顶部关联区)。
  • 下一步:以 Go 的工程约束与设计哲学 为总览,按需深入单个概念。

延伸阅读

资料类型说明
Go Proverbs(演讲站点)社区/演讲衍生谚语原始出处(Rob Pike, Gopherfest SV 2015)
Go at Google: Language Design in the Service of Software Engineering官方长文工程驱动设计的完整论述
Effective Go官方惯用法(未覆盖全部新特性)
Code Review CommentsWiki团队审查惯例,多谚语的工程落点
创建于 2026/8/2 更新于 2026/10/7
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本