go设置函数默认参数(函数选项模式)

在日常开发中,我们有时候需要使用默认设置,但有时候需要提供自定义设置 结构体/类,在Java我们可以使用无参、有参构造函数来实现,在PHP中我们也可以使用构造函数来实现(如 public function __construct($isCName = false, $securityToken = NULL, $requestProxy = NULL))。但在golang中无法这样做,不过我们可以使用另外一种方式优雅的实现。


1.举例

在这之前,我们在golang中大多是使用以下方式来实现的:

type ExampleClient struct {
	Name string
	Job int
}

func NewExampleClient(name, job string) ExampleClient {
	if name == "" {
		name = "default"
	}
	
	if job == "" {
		job = "default"
	}
	
	return ExampleClient{
		Name: name,
		Job:  job,
	}
}

这种方式侵入性比较强,如果此时我们需要增加一个超时参数或其他更多参数,那么需要在原代码基础上做很多的修改。


2.实现默认参数

在使用go-micro的过程中,发现其初始化服务配置的方式如下👇

func main() {
	sr := micro.NewService()
	//或
	sr := micro.NewService(
		micro.Name("xxx.xxx.xxx"),
		micro.Address("192.168.1.1"),
		)
}

进入到micro.NewService中,可以看到在初始化的过程中都是以type Option func(*Options)类型的函数作为参数,并调用newOptions方法👇

type Option func(*Options)

// NewService creates and returns a new Service based on the packages within.
func NewService(opts ...Option) Service {
	return newService(opts...)
}

func newService(opts ...Option) Service {
	options := newOptions(opts...)

	// service name
	serviceName := options.Server.Options().Name

	// wrap client to inject From-Service header on any calls
	options.Client = wrapper.FromService(serviceName, options.Client)

	return &service{
		opts: options,
	}
}

我们再接着进入到micro.newOptions中查看👇

type Options struct {
	Broker    broker.Broker
	Registry  registry.Registry
	...
}

func newOptions(opts ...Option) Options {
	opt := Options{
		Broker:    broker.DefaultBroker,
		Registry:  registry.DefaultRegistry,
		...
	}

	for _, o := range opts {
		o(&opt)
	}

	return opt
}

// Name of the service
func Name(n string) Option {
	return func(o *Options) {
		o.Server.Init(server.Name(n))
	}
}

// Address sets the address of the server
func Address(addr string) Option {
	return func(o *Options) {
		o.Server.Init(server.Address(addr))
	}
}

现在,我们知道了如何实现函数默认参数,最重要的步骤如下👇

//定义结构体
type ExampleClient struct {
	Name string
	Job string
}

//定义配置选项函数(关键)
type Option func(*ExampleClient)
func SetName(name string) Option {// 返回一个Option类型的函数(闭包):接受ExampleClient类型指针参数并修改之
	return func(this *ExampleClient) {
		this.Name = name
	}
}

//应用函数选项配置
func NewExampleClient(opts ...Option) ExampleClient{
	// 初始化默认值
	defaultClient := ExampleClient{
		Name: "default",
		Job:  "default",
	}

	// 依次调用opts函数列表中的函数,为结构体成员赋值
	for _, o := range opts {
		o(&defaultClient)
	}
	
	return defaultClient
}

这样利用闭包的特性,当我们需要额外添加参数时,只需要增加配置选项函数即可,拓展性很强。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值