你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

Golang 函数选项模式

2021/10/24 8:12:23

最近在使用Golang开发时遇到了一个问题,我想为某个函数的的某些参数设置一个默认值,这样当调用者调用这个函数使如果不需要或者没有设置默写参数就可以使用预先设置的默认值。这个需求很常用,在Python中很容易实现。

def client(conn, timeout=2, retries=3):
    pass
虽然这个需求很常用,但是Golang的函数不支持直接设置默认值。但是我们可以使用其他方式来实现。
package main

import (
	"fmt"
)

const (
	DEFAULT_TIMEOUT = 2
	DEFAULT_RETRIES = 3
)

type Client interface {
	DoSomething()
}

type Connection struct {
}

type client struct {
	conn    Connection
	timeout int // 超时时间(单位秒)
	retries int // 重试次数
}

func (c *client) DoSomething() {

}

// 默认参数方案一
// 使用两个构造函数,一个使用默认值, 一个根据传递的参数设置
//func NewClient(conn Connection) *client {
//	return &client{conn: conn, timeout: DEFAULT_TIMEOUT, retries: DEFAULT_RETRIES}
//}
//
//func NewClientWithOptions(conn Connection, timeout int, retries int) *client {
//	return &client{conn: conn, timeout: timeout, retries: retries}
//}

// 默认参数方案二
// 传入一个配置对象。
// 即使使用默认值也需要传递一默认对象(或者传递一个零值对象,然后再构造方法中判断)
// 但是默认对象中的值可能会在其他地方被修改
//type ClientOptions struct {
//	Timeout int
//	Retries int
//}
//
//var defaultClientOptions = ClientOptions{
//	Timeout: DEFAULT_TIMEOUT,
//	Retries: DEFAULT_RETRIES,
//}
//
//func NewClient(conn Connection, options ClientOptions) Client {
//	return &client{conn: conn, timeout: options.Timeout, retries: options.Retries}
//}

// 默认参数方案三
// 函数选项模式
var defaultClient = client{
	timeout: DEFAULT_TIMEOUT,
	retries: DEFAULT_RETRIES,
}

type ClientOption func(options *client)

func WithTimeout(t int) ClientOption {
	return func(o *client) {
		o.timeout = t
	}
}

func WithRetries(r int) ClientOption {
	return func(o *client) {
		o.retries = r
	}
}

func NewClient(conn Connection, opts ...ClientOption) Client {
	client := defaultClient
	for _, o := range opts {
		o(&client)
	}
	client.conn = conn
	return &client
}

func main() {
	x := NewClient(Connection{})
	fmt.Printf("%+v\n", x) // &{conn:{} timeout:2 retries:3}

	x = NewClient(Connection{}, WithRetries(5))
	fmt.Printf("%+v\n", x) // &{conn:{} timeout:2 retries:5}

	x = NewClient(Connection{}, WithTimeout(4), WithRetries(5))
	fmt.Printf("%+v\n", x) // &{conn:{} timeout:4 retries:5}
}