可选参数传递小技巧(option)

问题2

场景:假设你写的一个sdk在用户使用时,希望传入一些可选的参数,那么哪种传参写法更优雅呢?

现在假设你需要写一个发送消息的方法,这个方法包含一些可选参数,参数类型如下:

// 发送消息
type Options struct {
    FromUser string
    ToUser   string
    Content  string
    Type     string
}

常见做法
这个时候,这个个option如何传入创建连接的方法就有点小技巧了,常见的做法有以下几种:

  • 创建一个构造函数,不想要的参数就传一个空参。
    这种写法比较鸡肋,你需要严格按照参数列表和类型进行传参,虽然为空是缺省,但也不友好。

    func Send(fromUser string, touser string, Content string, Type string) {
      if fromUser == "" {
    
      }
      if touser == "" {
    
      }
      if Content == "" {
    
      }
      if Type == "" {
    
      }
    
      // do something
    }
  • 根据常见的可选组合创建多个options的构造函数。然后提供WithXXX的方法。
    这种写法还不错,可以选择性的传参,但是传参之前需要构造一个option,然后对option进行一些操作,其实也是有点麻烦的。
package main

import "fmt"

// 发送消息
type MessageParams struct {
    FromUser string
    ToUser   string
    Content  string
    Type     string
}

func NewMessageParams(fromUser, toUser string) *MessageParams {
    mp := &MessageParams{}
    mp.FromUser = fromUser
    mp.ToUser = toUser
    mp.Content = "单图"
    mp.Type = "img"

    //do something
    return mp
}

func (mp *MessageParams) WithContent(content string) {
    if content != "" {
        mp.Content = content
    }
}
func (mp *MessageParams) WithType(msgType string) {
    if msgType != "" {
        mp.Type = msgType
    }
}

func SendMessage(mp *MessageParams) {
    fmt.Printf("fromUser [%v] => toUser [%s] :type[%v] => content [%v]\n",
        mp.FromUser,
        mp.ToUser,
        mp.Type,
        mp.Content)
    // do something
}

func main() {
    mp := NewMessageParams("A", "B")
    mp.WithType("img")
    mp.WithContent("发送了一条单图消息")
    SendMessage(mp)
}

优雅做法

可以通过golang可选参数的形式,传入Option结构体(结构体中包含一个返回options指针的函数),动态的对参数进行构造。

这种写法在一些sdk中很常见。

package main
import "fmt"
// 发送消息
type MessageParams struct {
 FromUser string
 ToUser   string
 Content  string
 Type     string
}
type Option struct {
 f func(*MessageParams)
}
func WithContent(content string) Option {
 return Option{func(mp *MessageParams) {
  mp.Content = content
 }}
}
func WithType(msgType string) Option {
 return Option{func(mp *MessageParams) {
  mp.Type = msgType
 }}
}
func WithFromUser(fromUser string) Option {
 return Option{func(mp *MessageParams) {
  mp.FromUser = fromUser
 }}
}
func WithToUser(toUser string) Option {
 return Option{func(mp *MessageParams) {
  mp.ToUser = toUser
 }}
}
func SendMessage(ops ...Option) {
 mp := &MessageParams{}
 for _, do := range ops {
  do.f(mp)
 }
 fmt.Printf("fromUser [%v] => toUser [%s] :type[%v] => content [%v]\n",
  mp.FromUser,
  mp.ToUser,
  mp.Type,
  mp.Content)
 // do something
}
func main() {
 SendMessage(
  WithFromUser("A"),
  WithToUser("B"),
  WithContent("发送图片"),
  WithType("img"))
}

参考链接:
golang option可选传参小技巧

本作品采用《CC 协议》,转载必须注明作者和本文链接
白胖子
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!