阅读uber内部关于实践多年的golang编码规范,看到关于Function options的一条:

关于 functional options 简单来说就是通过类似闭包的方式来进行函数传参

不提倡

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// package db
 
func Connect( addr string, timeout time.Duration,
    caching bool) (*Connection, error) {
  // ...
}
 
// Timeout and caching must always be provided,
// even if the user wants to use the default.
 
db.Connect(addr, db.DefaultTimeout, db.DefaultCaching)
db.Connect(addr, newTimeout, db.DefaultCaching)
db.Connect(addr, db.DefaultTimeout, false /* caching */)
db.Connect(addr, newTimeout, false /* caching */)// package db

提倡:

 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
type options struct {
  timeout time.Duration
  caching bool
}
 
// Option overrides behavior of Connect.
type Option interface {
  apply(*options)
}
 
type optionFunc func(*options)
   
func (f optionFunc) apply(o *options) {
  f(o)
}
 
func WithTimeout(t time.Duration) Option {
  return optionFunc(func(o *options) { o.timeout = t })
}
 
func WithCaching(cache bool) Option {
  return optionFunc(func(o *options) { o.caching = cache })
}
 
// Connect creates a connection.
func Connect(addr string, opts ...Option,) (*Connection, error) {
  options := options{
    timeout: defaultTimeout,
    caching: defaultCaching,
  }
 
  for _, o := range opts {
      o.apply(&options)
  }
 
  // ...
}
 
// Options must be provided only if needed.
db.Connect(addr)
db.Connect(addr, db.WithTimeout(newTimeout))
db.Connect(addr, db.WithCaching(false))
db.Connect(addr, db.WithCaching(false), db.WithTimeout(newTimeout),
      )

golang对世界的抽象原语

联想到了c++和 go抽象方式的对比:

程序语言作为人与计算机之间的翻译官,需要完成对现实世界的抽象表达,然后转换为计算机理解的二进制指令,并执行。在二进制里完成现实世界的计算任务。更优雅的抽象能力,让程序语言表达能力更强,提升编码的效率。

  • struct => 有由xxxx构成的东西
  • interface => 会xxxx的东西
  • 匿名 =>东西的组装组合
  • 函数 => 谓词 :将xxxx处理成xxxx
  • 闭包 =>能够将xxxx处理成xxxx的东西(函数对象)

c++提供了函数重载和默认函数等方式来实现这种方式的可变参数调用,但是golang没有提供函数重载的能力

如何理解下面的这个函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func Connect(addr string, opts ...Option,) (*Connection, error)

// Option => 一种会处理apply 选项的东西
type Option interface {
  apply(*options)
}

// 输入: 一个时间,输出:一个具有"将Options的超时时间设置为输入时间"能力的东西
func WithTimeout(t time.Duration) Option



参考: