Saki's 研究记录

使用结构或函数选项简化go函数签名【译】

字数统计: 735阅读时长: 2 min
2025/01/07

文章内容来自func25twitter

Go中设计函数时,我们可能会遇到需要传递大量参数的情况。

1
2
3
func ConnectToService(host, username, password string, port int, ssl bool) {
// Connection logic ...
}

这可能会影响函数的目的,并使维护代码成为一件苦差事,特别是当涉及相同类型的参数时。 为了保持整洁,请考虑两种策略:

  • 选项结构
  • 函数选项

选项结构体

将参数捆绑到一个结构中,这不仅增强了可读性,还简化了参数传递。

什么时候使用它?

  • 你的函数有一个很长的参数列表。
  • 您的目标是自记录代码,因为结构字段本质上描述了它们的用途(通过名称)。
  • 您希望轻松设置默认值或灵活修改选项。
1
2
3
4
5
6
7
8
9
10
11
type ServiceOPtios struct {
Host string
Port int
Username string
Password string
SSL bool
}

func ConnectToService(options ServiceOptions) {
// Connection logic ...
}

使用此模式时,context.Context 应保留为单独的参数,而不应包含在选项结构中。

1
2
3
func ConnectToService(ctx context.Context, options ServiceOPtions) {
// Connection logic ...
}

这是由于上下文在控制请求范围值、截止日期和取消信号方面的独特作用。 但在使用时有一些小技巧:

  • 该结构应该向后兼容,以便在添加新字段时,我们不会破坏之前的任何内容。
  • 我们始终可以在处理结构之前对其进行验证。
  • 考虑隐藏您的选项结构(使其不导出),然后公开 NewXXX() 函数并在那里设置默认值。

函数选项(Functional Options)

此方法利用 Go 的函数功能,允许您以更简洁的方式传递灵活数量的选项。

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
type ServiceConfig struct {
host string
port int
ssl bool
}

type ServiceOPtion func(*ServiceConfig)

func WithHost(host string) ServiceOPtion {
return func(cfg *ServiceOption) {
cfg.host = host
}
}

func WithPort(port int) ServiceOPtion {
return func(cfg *ServiceOption) {
cfg.port = port
}
}

func WithSSL(ssl bool) ServiceOPtion {
return func(cfg *ServiceOption) {
cfg.ssl = ssl
}
}

func ConnectToDatabase(options ...ServiceOPtion) {
cfg := ServiceConfig{}
for _, option := range options {
option(&cfg)
}

// Connect using cfg ...
}

// Usage:
// ConnectToDatabase(WithHost(`127.0.0.1`), WithPort(1024), WithSSL(true))

上面这组代码传入一个参数,然后返回一个函数,返回的这个函数会设置自己的 ServiceOption 参数。例如:
• 当我们调用其中的一个函数用 WithSSL(true) 时
• 其返回值是一个 func(cfg* ServiceOption) { cfg.ssl = true } 的函数。

设置默认值比使用可选结构更容易,您不需要隐藏它,只需将默认值直接放在 ConnectToDatabase 中即可。

以上。

CATALOG
  1. 1. 选项结构体
    1. 1.1. 什么时候使用它?
  2. 2. 函数选项(Functional Options)