Go Proverbs(Go 谚语)

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

#type / synthesis #status / growing #tech / dev #resource / go

[!info] 关联笔记

Go Proverbs(Go 谚语)

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

读这些谚语时记住一件事:它们是方向,不是禁令。例如「通过通信共享内存」并不禁止你用 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 The default Go concurrency story is: pass ownership of data through a channel between goroutines, rather than having many goroutines read and write the same memory region guarded by locks. “Share memory by communicating” means the data moves — its ownership is transferred — instead of being contended for.

中文 Go 并发的默认范式是:用 channel 在 goroutine 之间传递数据所有权,而不是让多个 goroutine 用锁去抢同一块内存。「通过通信来共享内存」的核心在于——数据被移动(所有权被移交),而不是被争抢。channel 天然规定了「谁在何时拥有这块数据」,从而把竞态从设计层面消减。

关联 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 — few real types qualify, and the contract says less. 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; a slice/map zero value is nil but often safe to range over or append to. Design types so their zero value is a valid, ready state.

中文 类型的零值(如 0、空字符串,或零值结构体)应当无需额外初始化即可使用。例如:sync.Mutex 的零值已可直接加锁;bytes.Buffer 的零值是一个空的、可用的缓冲区;slice/map 的零值是 nil,但通常可以安全地对它 rangeappend。设计类型时应让零值处于合法、就绪状态。

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

interface{} says nothing.

interface{} 什么也说不出来。

EN The empty interface interface{} (now spelled any) accepts any type but carries zero information about what it holds. You lose static type safety and must type-assert at runtime. Use it sparingly; prefer concrete types, generics, or a small purpose-built interface.

中文 空接口 interface{}(现在写作 any)能接收任何类型,但携带零信息——它不说明里面到底是什么。你失去了静态类型安全,必须在运行时做类型断言。应谨慎使用;优先选具体类型、泛型,或一个小而专用的接口。

关联 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 keeps your build decoupled from an external package you don’t control.

中文 与其为了一点小需求就引入一个依赖(带来维护、版本与供应链成本),不如复制一小段简单代码。复制让你不必把构建耦合到一个你无法控制的外部包上。

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


边界代码

Syscall must always be guarded with build tags.

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

EN Code that calls OS syscalls is platform-specific. Guard it with build constraints (//go:build) so it only compiles on the intended OS/arch, keeping the rest of the build portable and cross-compilable.

中文 调用操作系统 syscall 的代码是平台相关的。用构建约束(//go:build)守护它,使其只在目标 OS/架构下编译,从而保持其余构建的可移植性与可交叉编译性。

关联 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. Guard it with build constraints so a pure-Go build remains possible and the C dependency is isolated to the files that need it.

中文 cgo 桥接 C,代价高且平台相关。必须用构建约束守护,以便纯 Go 构建仍可成立,并把 C 依赖隔离到真正需要它的文件里。

关联 go-cgo

Cgo is not Go.

cgo 不是 Go。

EN Cgo code crosses the language boundary: it breaks Go’s uniform build model, its GC assumptions, and effortless cross-compilation. Treat it as a foreign dependency, not as idiomatic Go, and keep it behind a small, well-fenced surface.

中文 cgo 代码跨越了语言边界:它破坏 Go 统一的构建模型、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 compiler makes no promises about behavior across Go versions, and a mistake yields undefined behavior or a crash. Reach for it only when absolutely necessary, and fence it tightly.

中文 unsafe 包绕过了 Go 的类型与内存安全。编译器对跨版本的行为不作任何承诺,一旦出错就是未定义行为甚至崩溃。除非绝对必要,否则不要用;若用,必须严密封装。

关联 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 obscures types, defeats static checks, and hurts performance. It is never as clear as explicitly typed code. Avoid it unless there is no cleaner alternative.

中文 反射(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 Use panic only for truly unrecoverable programmer errors. For ordinary failures, return an error. panic aborts the normal control flow and is hard to reason about; library code should rarely, if ever, panic.

中文 panic 只应用于真正不可恢复的编程错误。普通失败应返回 errorpanic 会中断正常控制流、难以推理;库代码尤其不应随意 panic。

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


本节总结

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

延伸阅读

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