Golang中可选函数/方法参数的使用探讨

Golang中可选函数/方法参数的使用探讨 我想知道在调用函数/方法时允许可选参数的最佳方式是什么——实际上我的想法是,我不想强制用户设置那些在函数内部会被类似 time.Sleep 使用的值……

func f(delay time.Duration) {
  time.Sleep(delay)
  fmt.Println("I slept for", delay)
}

如果我想调用函数 f(),即使我不想要/不需要设置延迟,因为 time.Duration 的默认值是 int64(0),而且如果我不想设置延迟,那么 0 对我来说是可以接受的,但我仍然必须提供一个延迟 f(time.Duration(0))

有什么建议吗?也许可以不用可变函数参数,因为参数可能是不同的"类型",例如混合多个(可选)延迟和可选的 func() 等?

这里有一个示例:https://play.golang.org/p/xSeiaWwh2cX

谢谢! Alex


更多关于Golang中可选函数/方法参数的使用探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

更多关于Golang中可选函数/方法参数的使用探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


谢谢 @GreyShatter@NobbZ

看起来这并不那么简单,特别是当你可能有4-5个可选参数时。

我将提供两个函数:ffDelayed

func f() {
  fDelayed(time.Duration(0))
}

func fDelayed(delay time.Duration) {
  time.Sleep(delay)
  fmt.Println("I slept for", delay)
}

可以使用 map 参数作为可变参数函数的替代方案。

func f(arg map[string]YourType) {
}

这样,用户可以传入带标签的输入,或者直接传入 nil 作为输入。

f(nil)
f(map[string]YourType{ "delay" = 4*time.Duration}) 
f(map[string]YourType{ "delay" = 4*time.Duration, "acceleration" = 10.time.Duration, ... }) 
--- 更清晰的写法 ---
options = map[string]YourType {
    "delay" = 4*time.Duration,
    ...
}
f(options)
---------------

Go 语言没有完整的可选参数功能,所以如果你想提供无参数选项作为其中一个选择,NobbZ 的方法将是最佳方案。

在Go语言中处理可选参数有多种方式,以下是几种实用的方法:

1. 使用配置结构体(推荐)

这是最常用且可读性最好的方式:

type Config struct {
    Delay   time.Duration
    Callback func()
    Retries int
}

func NewConfig() Config {
    return Config{
        Delay:   0,           // 默认值
        Retries: 3,           // 默认值
    }
}

func f(cfg Config) {
    time.Sleep(cfg.Delay)
    fmt.Printf("I slept for %v, retries: %d\n", cfg.Delay, cfg.Retries)
    
    if cfg.Callback != nil {
        cfg.Callback()
    }
}

// 使用示例
func main() {
    // 使用默认配置
    f(NewConfig())
    
    // 自定义部分参数
    cfg := NewConfig()
    cfg.Delay = 2 * time.Second
    cfg.Callback = func() { fmt.Println("Callback executed!") }
    f(cfg)
    
    // 内联配置
    f(Config{
        Delay: time.Second,
        Retries: 5,
    })
}

2. 使用可变参数和选项函数模式

这种方法在标准库和许多第三方库中广泛使用:

type Option func(*options)

type options struct {
    delay   time.Duration
    callback func()
    retries int
}

func WithDelay(d time.Duration) Option {
    return func(o *options) {
        o.delay = d
    }
}

func WithCallback(cb func()) Option {
    return func(o *options) {
        o.callback = cb
    }
}

func WithRetries(r int) Option {
    return func(o *options) {
        o.retries = r
    }
}

func f(opts ...Option) {
    // 默认配置
    config := &options{
        delay:   0,
        retries: 3,
    }
    
    // 应用选项
    for _, opt := range opts {
        opt(config)
    }
    
    time.Sleep(config.delay)
    fmt.Printf("I slept for %v, retries: %d\n", config.delay, config.retries)
    
    if config.callback != nil {
        config.callback()
    }
}

// 使用示例
func main() {
    // 无参数
    f()
    
    // 单个可选参数
    f(WithDelay(2 * time.Second))
    
    // 多个可选参数
    f(
        WithDelay(time.Second),
        WithCallback(func() { fmt.Println("Done!") }),
        WithRetries(5),
    )
}

3. 使用指针参数

对于简单的可选参数,可以使用指针:

func f(delay *time.Duration) {
    var actualDelay time.Duration
    if delay != nil {
        actualDelay = *delay
    }
    
    time.Sleep(actualDelay)
    fmt.Println("I slept for", actualDelay)
}

// 使用示例
func main() {
    // 不提供延迟
    f(nil)
    
    // 提供延迟
    delay := 2 * time.Second
    f(&delay)
}

4. 针对你的具体示例的简单解决方案

对于你的f()函数,最简单的修改是:

func f(delay ...time.Duration) {
    var d time.Duration
    if len(delay) > 0 {
        d = delay[0]
    }
    
    time.Sleep(d)
    fmt.Println("I slept for", d)
}

// 使用示例
func main() {
    f()                    // 使用默认值0
    f(2 * time.Second)     // 提供自定义延迟
}

配置结构体方法是最推荐的,因为它提供了最好的类型安全性和可读性,同时便于扩展和维护。选项函数模式在需要高度灵活性的库中也很受欢迎。

回到顶部