当前位置: 首页 > backend >正文

Golang实现函数默认参数

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() {
printMessage(“Hello, World!”) // 使用不带默认参数的函数
printMessageWithDefault(“”) // 使用带默认参数的函数,传入空字符串触发默认值
printMessageWithDefault(“”, “Default”) // 明确指定默认值
}
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 stringJob 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 nameserviceName := options.Server.Options().Name// wrap client to inject From-Service header on any callsoptions.Client = wrapper.FromService(serviceName, options.Client)return &service{opts: options,}
}

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

type Options struct {Broker    broker.BrokerRegistry  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 stringJob 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 mainimport "fmt"//如何向func传递默认值type dialOption struct {Username stringPassword stringService  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 intdopts dialOption
}func NewClient(address string, opts ...DialOption){cc :=&clientConn{timeout:30,dopts:defaultOptions(),}//循环调用optsfor _,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的方式来修改的。
唯一不好的地方可能是代码量相应的增加了。但是为了更优雅,这种做法还是值得的。

http://www.xdnf.cn/news/2743.html

相关文章:

  • 人工智能数学基础(一):人工智能与数学
  • 动态规划问题 -- 斐波那契数列模型(解码方法)
  • etcd 的安装及使用
  • 软件评测师考点重点知识
  • ubuntu安装docker,conda,tmux,btop,nvitop
  • 一种用于从视网膜图像中识别疾病的 BERT 式自监督学习 CNN
  • 大模型训练平台:重构 AI 研发范式的智慧基建
  • MCU内存映射技术详解
  • python数据分析(五):Pandas 数据检索技术
  • 鸢尾花(Iris)数据集的多模型分类与可视化分析工具
  • openai agents sdk实战-基于Ollama+qwen2.5+milvus+bge-large-zh-v1.5实现本地知识库
  • 在 C# .NET 中驾驭 JSON:使用 Newtonsoft.Json 进行解析与 POST 请求实战
  • 动态规划
  • 在g2o中,顶点(Vertex)和边(Edge)插入到概率图的流程
  • 迈瑞医疗:国际业务增长21.28% 发展中国家成重要增长引擎
  • 如何修复卡在恢复模式下的 iPhone:简短指南
  • 配置管理平台Nacos01:基础安装教程和启动运行
  • 第十五届中国国际道路交通安全产品博览会回顾
  • 2025年ISA Trans SCI2区TOP:超级哈里斯鹰算法Super-HHO+高功率机车悬挂载荷偏差控制,深度解析+性能实测
  • 5G育种技术之植物性状订制
  • 智慧健康养老实训室建设方案:科技引领养老健康服务人才培养
  • 第十六节:开放性问题-Vue与React Hooks对比
  • 使用阿里云 CDN 保护网站真实 IP:完整配置指南
  • Wireshark快速入门--对启动的后端程序进行抓包
  • 杰里芯片 7083G 之通话数据dump
  • Java基础361问第16问——枚举为什么导致空指针?
  • GPU虚拟化实现(五)
  • LeetCode热题100--560.和为K的子数组(前缀和)--中等
  • 自动化测试的三种等待方式
  • 算法笔记.染色法判断二分图