golang原生不支持默認參數
在日常開發中,我們有時候需要使用默認設置,但有時候需要提供自定義設置 結構體/類,在Java我們可以使用無參、有參構造函數來實現,在PHP中我們也可以實現(如 public function xxx($isCName = false, $securityToken = NULL, $requestProxy = NULL))。但在golang中無法這樣做,不過我們可以使用另外一種方式優雅的實現。
golang如何模擬實現默認參數?
在 Go 語言中,函數參數默認值的概念與某些其他編程語言(如 Python)略有不同。Go 語言本身不支持在函數定義中直接為參數設置默認值,這與 Python 或 Java 等語言不同。不過,你可以通過幾種方式模擬出類似的功能:
- 使用函數重載
雖然 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的方式來修改的。
唯一不好的地方可能是代碼量相應的增加了。但是為了更優雅,這種做法還是值得的。