Golang实现函数默认参数

06-01 1371阅读

golang原生不支持默认参数

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

golang如何模拟实现默认参数?

在 Go 语言中,函数参数默认值的概念与某些其他编程语言(如 Python)略有不同。Go 语言本身不支持在函数定义中直接为参数设置默认值,这与 Python 或 Java 等语言不同。不过,你可以通过几种方式模拟出类似的功能:

  1. 使用函数重载

    虽然 Go 不支持传统意义上的重载(即多个函数名相同但参数不同的定义),但你可以通过不同的函数名来实现类似的效果。

package main

import “fmt”

// 定义两个函数,一个带默认参数,一个不带

func printMessage(message string) {

fmt.Println(“Default message:”, message)

}

func printMessageWithDefault(message string, defaultMessage …string) {

if message == “” && len(defaultMessage) > 0 {

message = defaultMessage[0]

}

fmt.Println(“Custom message:”, message)

}

func main() {

Golang实现函数默认参数
(图片来源网络,侵删)

printMessage(“Hello, World!”) // 使用不带默认参数的函数

printMessageWithDefault(“”) // 使用带默认参数的函数,传入空字符串触发默认值

Golang实现函数默认参数
(图片来源网络,侵删)

printMessageWithDefault(“”, “Default”) // 明确指定默认值

}

Golang实现函数默认参数
(图片来源网络,侵删)

2. 使用可变参数和切片

如果你想要一个函数可以有或没有参数,可以考虑使用可变参数或切片。

package main

import “fmt”

func printMessages(messages …string) {

if len(messages) == 0 {

fmt.Println(“No messages provided”)

} else {

for _, msg := range messages {

fmt.Println(msg)

}

}

}

func main() {

printMessages(“Hello”, “World”) // 传入多个消息

printMessages() // 不传入任何消息,显示默认行为

}

3. 使用结构体和指针传递默认值

对于更复杂的情况,可以使用结构体和指针来传递默认值。

package main

import “fmt”

type Config struct {

Message string

}

func printMessage(config *Config) {

if config == nil {

fmt.Println(“Using default message”)

config = &Config{Message: “Default message”} // 设置默认值并传递指针引用

}

fmt.Println(config.Message)

}

func main() {

printMessage(nil) // 使用默认值,因为没有传递非nil的Config实例

config := Config{Message: “Custom message”}

printMessage(&config) // 使用自定义消息

}

4. 使用工厂函数或构造函数模式

创建一个工厂函数或构造函数来返回一个已经配置好的实例。

package main

import “fmt”

type MessagePrinter struct {

message string

}

func NewMessagePrinter(message string) *MessagePrinter {

if message == “” { // 检查是否需要默认值

message = “Default message” // 设置默认值

}

return &MessagePrinter{message: message} // 返回实例指针,包含配置好的消息值

}

func (mp *MessagePrinter) Print() {

fmt.Println(mp.message) // 打印消息内容

}

func main() {

mp1 := NewMessagePrinter(“”) // 使用默认值创建实例

mp1.Print() // 打印默认消息

mp2 := NewMessagePrinter(“Custom message”) // 使用自定义消息创建实例并

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
}

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

————————————————

版权声明:本文为CSDN博主「johopig」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/zhetmdoubeizhanyong/article/details/106414205

我们看下用Functional Options Patter的方式,我写了一个简单的例子。

package main
import "fmt"
//如何向func传递默认值
type dialOption struct {
	Username string
	Password string
	Service  string
}
type DialOption interface {
	apply(*dialOption)
}
type funcOption struct {
	f func(*dialOption)
}
func(fdo *funcOption) apply(do *dialOption){
	 fdo.f(do)
}
func newFuncOption(f func(*dialOption))*funcOption{
	return &funcOption{
		f:f,
	}
}
func withUserName(s string) DialOption{
	return  newFuncOption(func(o *dialOption){
		o.Username = s
	})
}
func withPasswordd(s string) DialOption{
	return  newFuncOption(func(o *dialOption){
		o.Password = s
	})
}
func withService(s string) DialOption{
	return  newFuncOption(func(o *dialOption){
		o.Service = s
	})
}
//默认参数
func defaultOptions() dialOption{
	return dialOption{
		Service:"test",
	}
}
type clientConn struct {
	timeout int
	dopts dialOption
}
func NewClient(address string, opts ...DialOption){
	cc :=&clientConn{
		timeout:30,
		dopts:defaultOptions(),
	}
	//循环调用opts
	for _,opt := range opts {
		opt.apply(&cc.dopts)
	}
	fmt.Printf("%+v",cc.dopts)
}
func main(){
	NewClient("127.0.0.1",withPasswordd("654321"),withService("habox"))
	NewClient("127.0.0.1",withService("habox"))
}

实例化时,通过func的方式来传递参数,也可以定义一些默认参数。如果以后要加,只需要更改很少的代码。

而且,这种方式也不会传递不相关的参数,因为参数都在通过func的方式来修改的。

唯一不好的地方可能是代码量相应的增加了。但是为了更优雅,这种做法还是值得的。

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码