惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

罗磊的独立博客
U
Unit 42
N
Netflix TechBlog - Medium
人人都是产品经理
人人都是产品经理
Hugging Face - Blog
Hugging Face - Blog
腾讯CDC
小众软件
小众软件
V
Visual Studio Blog
T
Tailwind CSS Blog
Engineering at Meta
Engineering at Meta
博客园 - 叶小钗
GbyAI
GbyAI
爱范儿
爱范儿
雷峰网
雷峰网
Microsoft Azure Blog
Microsoft Azure Blog
D
DataBreaches.Net
博客园_首页
D
Docker
A
About on SuperTechFans
G
Google Developers Blog
I
InfoQ
T
The Blog of Author Tim Ferriss
V
V2EX
博客园 - Franky

鸟窝

鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 鸟窝 LLM 究竟是如何工作的? Go 实验特性详解
Go之禅 - 基于Rob Pike思想的Go语言哲学
by smallnest · 2025-11-01 · via 鸟窝

Go之禅 - 基于Rob Pike思想的Go语言哲学

1. 简单胜过聪明 (Simple is better than clever)

不要炫技,要解决问题

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

func Max(a, b int) int {

if a > b {

return a

}

return b

}

func Max(a, b int) int {

return (a + b + abs(a-b)) / 2

}

func abs(x int) int {

if x < 0 {

return -x

}

return x

}

2. 清晰胜过简洁 (Clear is better than concise)

代码首先要让人读懂

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

func CalculateUserScore(user *User) int {

totalPoints := 0

for _, activity := range user.Activities {

totalPoints += activity.Points

}

if len(user.Activities) == 0 {

return 0

}

return totalPoints / len(user.Activities)

}

func CalcScore(u *User) int {

if len(u.Acts) == 0 { return 0 }

return func() int { s := 0; for _, a := range u.Acts { s += a.Pts }; return s }() / len(u.Acts)

}

3. 组合胜过继承 (Composition over inheritance)

Go的接口和嵌入体现组合思想

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

type Writer interface {

Write([]byte) (int, error)

}

type Logger interface {

Log(string)

}

type FileLogger struct {

writer Writer

prefix string

}

func (f *FileLogger) Log(message string) {

f.writer.Write([]byte(f.prefix + message))

}

type NetworkLogger struct {

writer Writer

endpoint string

}

func (n *NetworkLogger) Log(message string) {

n.writer.Write([]byte(n.endpoint + ": " + message))

}

4. 接口要小而专注 (Interfaces should be small and focused)

接口越小越好,单一职责

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

type Reader interface {

Read([]byte) (int, error)

}

type Writer interface {

Write([]byte) (int, error)

}

type Closer interface {

Close() error

}

type ReadWriter interface {

Reader

Writer

}

type ReadWriteCloser interface {

Reader

Writer

Closer

}

type FileHandler interface {

Read([]byte) (int, error)

Write([]byte) (int, error)

Seek(int64, int) (int64, error)

Close() error

Stat() (os.FileInfo, error)

Chmod(os.FileMode) error

}

5. 并发不是并行 (Concurrency is not parallelism)

并发是关于结构,并行是关于执行

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

func ProcessTasks(tasks []Task) {

taskChan := make(chan Task, len(tasks))

resultChan := make(chan Result, len(tasks))

for i := 0; i < 3; i++ {

go worker(taskChan, resultChan)

}

for _, task := range tasks {

taskChan <- task

}

close(taskChan)

for i := 0; i < len(tasks); i++ {

result := <-resultChan

fmt.Printf("任务完成: %v\n", result)

}

}

func worker(tasks <-chan Task, results chan<- Result) {

for task := range tasks {

result := processTask(task)

results <- result

}

}

Channel是Go的核心哲学

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

type Counter struct {

ch chan int

value int

}

func NewCounter() *Counter {

c := &Counter{

ch: make(chan int),

}

go c.run()

return c

}

func (c *Counter) run() {

for increment := range c.ch {

c.value += increment

}

}

func (c *Counter) Increment() {

c.ch <- 1

}

func (c *Counter) Add(n int) {

c.ch <- n

}

type MutexCounter struct {

mu sync.Mutex

value int

}

func (c *MutexCounter) Increment() {

c.mu.Lock()

defer c.mu.Unlock()

c.value++

}

7. 错误是值,不是异常 (Errors are values, not exceptions)

显式错误处理胜过异常

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

func ReadConfig(filename string) (*Config, error) {

data, err := os.ReadFile(filename)

if err != nil {

return nil, fmt.Errorf("读取配置文件失败: %w", err)

}

var config Config

if err := json.Unmarshal(data, &config); err != nil {

return nil, fmt.Errorf("解析配置失败: %w", err)

}

return &config, nil

}

func main() {

config, err := ReadConfig("config.json")

if err != nil {

log.Fatal(err)

}

}

8. 不要设计大型接口 (Don't design with interfaces, discover them)

接口应该从使用中发现,而不是预先设计

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

type FileStorage struct {

basePath string

}

func (f *FileStorage) Save(key string, data []byte) error {

return os.WriteFile(filepath.Join(f.basePath, key), data, 0644)

}

func (f *FileStorage) Load(key string) ([]byte, error) {

return os.ReadFile(filepath.Join(f.basePath, key))

}

type Storage interface {

Save(string, []byte) error

Load(string) ([]byte, error)

}

9. 空接口什么都不说 (The empty interface says nothing)

避免过度使用interface{}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

func ProcessUsers(users []User) {

for _, user := range users {

fmt.Printf("处理用户: %s\n", user.Name)

}

}

type Processor interface {

Process() error

}

func RunProcessors(processors []Processor) {

for _, p := range processors {

if err := p.Process(); err != nil {

log.Printf("处理失败: %v", err)

}

}

}

func ProcessAnything(items []interface{}) {

for _, item := range items {

switch v := item.(type) {

case User:

fmt.Printf("用户: %s\n", v.Name)

case Product:

fmt.Printf("产品: %s\n", v.Name)

default:

fmt.Printf("未知类型: %T\n", v)

}

}

}

10. Gofmt的风格就是每个人的风格 (Gofmt's style is no one's favorite, yet gofmt is everyone's favorite)

统一的代码格式胜过个人偏好

1

2

3

4

5

6

7

8

9

10

11

12

13

func CalculateTotal(items []Item, taxRate float64) float64 {

var subtotal float64

for _, item := range items {

subtotal += item.Price * float64(item.Quantity)

}

tax := subtotal * taxRate

return subtotal + tax

}

11. 小规模清晰胜过大规模复杂 (A little copying is better than a little dependency)

适度的代码重复胜过不必要的依赖

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

package userservice

func ValidateEmail(email string) bool {

return strings.Contains(email, "@") && len(email) > 5

}

package orderservice

func ValidateEmail(email string) bool {

return strings.Contains(email, "@") && len(email) > 5

}

12. 系统调用、操作系统线程和互斥锁的代价很高,尽量避免 (Syscalls, OS threads, and mutexes are expensive)

理解并发原语的成本

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

func FanOut(input <-chan int, workers int) <-chan int {

output := make(chan int)

for i := 0; i < workers; i++ {

go func() {

for n := range input {

result := process(n)

output <- result

}

}()

}

return output

}

type ExpensiveCounter struct {

mu sync.Mutex

value int

}

func (c *ExpensiveCounter) Get() int {

c.mu.Lock()

defer c.mu.Unlock()

return c.value

}

func (c *ExpensiveCounter) Set(v int) {

c.mu.Lock()

defer c.mu.Unlock()

c.value = v

}

13. 缓存是有用的 (Caching is important)

但要简单明了

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

type Cache struct {

mu sync.RWMutex

data map[string]interface{}

}

func NewCache() *Cache {

return &Cache{

data: make(map[string]interface{}),

}

}

func (c *Cache) Get(key string) (interface{}, bool) {

c.mu.RLock()

defer c.mu.RUnlock()

value, exists := c.data[key]

return value, exists

}

func (c *Cache) Set(key string, value interface{}) {

c.mu.Lock()

defer c.mu.Unlock()

c.data[key] = value

}

var userCache = NewCache()

func GetUser(id string) (*User, error) {

if cached, ok := userCache.Get(id); ok {

return cached.(*User), nil

}

user, err := fetchUserFromDB(id)

if err != nil {

return nil, err

}

userCache.Set(id, user)

return user, nil

}

14. 测试先行,但不要过度测试 (Test first, but don't over-test)

测试重要行为,不是实现细节

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

func TestCalculateDiscount(t *testing.T) {

tests := []struct {

name string

amount float64

userType string

want float64

}{

{"普通用户无折扣", 100.0, "regular", 100.0},

{"VIP用户9折", 100.0, "vip", 90.0},

{"金牌用户8折", 100.0, "gold", 80.0},

}

for _, tt := range tests {

t.Run(tt.name, func(t *testing.T) {

got := CalculateDiscount(tt.amount, tt.userType)

if got != tt.want {

t.Errorf("CalculateDiscount() = %v, want %v", got, tt.want)

}

})

}

}

func TestCalculateDiscountInternals(t *testing.T) {

}

15. 如果你觉得需要泛型,请三思 (If you think you need generics, think again)

Go 1.18+有了泛型,但要谨慎使用

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

func Map[T, U any](slice []T, fn func(T) U) []U {

result := make([]U, len(slice))

for i, v := range slice {

result[i] = fn(v)

}

return result

}

func Filter[T any](slice []T, predicate func(T) bool) []T {

var result []T

for _, v := range slice {

if predicate(v) {

result = append(result, v)

}

}

return result

}

numbers := []int{1, 2, 3, 4, 5}

doubled := Map(numbers, func(x int) int { return x * 2 })

evens := Filter(numbers, func(x int) bool { return x%2 == 0 })

type GenericProcessor[T, U, V, W any] interface {

Process(T, U) (V, W, error)

Validate(T) bool

Transform(U) V

}

16. 性能问题通常出在算法,不是语言 (Performance problems are usually algorithmic)

优化算法比优化语言特性更重要

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

func FindDuplicates(nums []int) []int {

seen := make(map[int]bool)

var duplicates []int

for _, num := range nums {

if seen[num] {

duplicates = append(duplicates, num)

} else {

seen[num] = true

}

}

return duplicates

}

func FindDuplicatesSlow(nums []int) []int {

var duplicates []int

for i := 0; i < len(nums); i++ {

for j := i + 1; j < len(nums); j++ {

if nums[i] == nums[j] {

duplicates = append(duplicates, nums[i])

break

}

}

}

return duplicates

}

17. 数据结构,不是算法,才是编程的核心 (Data structures, not algorithms, are central to programming)

正确的数据结构让程序简单明了

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

type UserIndex struct {

byID map[string]*User

byEmail map[string]*User

users []*User

}

func NewUserIndex() *UserIndex {

return &UserIndex{

byID: make(map[string]*User),

byEmail: make(map[string]*User),

users: make([]*User, 0),

}

}

func (ui *UserIndex) AddUser(user *User) {

ui.byID[user.ID] = user

ui.byEmail[user.Email] = user

ui.users = append(ui.users, user)

}

func (ui *UserIndex) FindByID(id string) *User {

return ui.byID[id]

}

func (ui *UserIndex) FindByEmail(email string) *User {

return ui.byEmail[email]

}

func (ui *UserIndex) GetAllUsers() []*User {

return ui.users

}

type BadUserStorage struct {

users []*User

}

func (us *BadUserStorage) FindByID(id string) *User {

for _, user := range us.users {

if user.ID == id {

return user

}

}

return nil

}


Go之禅总结: Go语言强调简单、清晰、组合和并发。Rob Pike的设计哲学体现在语言的每个角落:小而专注的接口、显式的错误处理、通过通信共享内存的并发模型,以及对简单性的坚持。Go不追求语言特性的丰富性,而是追求解决实际问题的有效性。