在日常的Go程序开发中,函数(方法)参数的传递是必不可少的一部分,如果参数比较少,可以在方法参数部分直接列出,如果参数很多,可不可以一个一个罗列呢,答案是可以的。但是这种方式存在两个问题:

  1. 参数很多,罗列出来之后方法的参数部分会很长,不美观;
  2. 每一个参数都有对应的数据类型,太多的参数在函数(方法)调用的时候容易写错顺序;

    func Test(a []int, b, c,d string, e, f, g, h int) {  // 存在多个参数类型
    
    }

既然存在上边两个问题,我们来优化一下,这些参数可以放在一个结构体里,通过结构体传递参数,如下:

type param struct {
  a []int
  b string
  c string
  d string
  e int
}
func Test(p param) {

}

通过上边的优化就可以解决第一种方式存在的问题,优化后的方式也是在传参中的比较常用的。我们继续思考一下,如果在开发中我们有可选参数的需求呢,这种需求在初始化结构体的时候会比较常见,有部分参数是必须在初始化的时候传递的,而另外一部分参数则是不同的调用方传递不同的可选参数。针对这种场景方法二也可以解决,在初始化的时候把程序用到的所有参数都初始化,但是这种处理并不满足可选参数的需求。Go原生并没有像Python等语言一样支持可选参数,需要开发者自己来实现,这个时候就需要用到选项模式了。如下:

type Base struct {
  Id     string
  Name   string
  Age    int
  School string
  Record string
}

type Options func(*Base)

func WithAge(age int) Options {
  return func(base *Base) {
      base.Age = age
  }
}

func WithSchool(school string) Options {
  return func(base *Base) {
      base.School = school
  }
}

func WithRecord(record string) Options {
  return func(base *Base) {
      base.Record = record
  }
}

func New(id, name string, opt ...Options) *Base {
  base := &Base{
      Id:   id,
      Name: name,
  }
  for _, op := range opt {
      op(base)
  }
  return base
}

在上边的程序中,Id和Name两个字段是在初始化的时候需要要传递的,其他的字段则是可选的,那么其他的字段就可以创建自己的With方法,在初始化的时候通过下边的方式来调用,需要用到哪个可选参数,就调用对应的With方法即可,如下:

func TestNew(t *testing.T) {
    New("123", "黎明", WithAge(12), WithRecord("3.1"))
}

到这里参数传递就比较能满足日常的大部分需求,但是我们不能止步于此。再深想一下,如果可选参数在初始化的时候有可能发生错误,这种场景怎么处理?针对这种场景,就需要添加错误处理机制了,如下:

type Base struct {
    Id     string
    Name   string
    Age    int
    School string
    Record string
}

type Options func(*Base) error

func WithAge(age int) Options {
    return func(base *Base) error {
        if age <= 0 {
            return errors.New("年龄不能小于1岁")
        }
        base.Age = age
        return nil
    }
}

func WithSchool(school string) Options {
    return func(base *Base) error {
        base.School = school
        return nil
    }
}

func WithRecord(record string) Options {
    return func(base *Base) error {
        base.Record = record
        return nil
    }
}

func New(id, name string, opt ...Options) (*Base, error) {
    base := &Base{
        Id:   id,
        Name: name,
    }
    for _, op := range opt {
        err := op(base)
        if err != nil {
            return nil, err
        }
    }
    return base, nil
}

调用如下:

func TestNew(t *testing.T) {
    _, err := New("123", "黎明", WithAge(12), WithRecord("3.1"))
    if err != nil {
        return
    }
}

至此,方法参数传递和可选参数就完成,以上的四种方式可以满足大部分场景了。至于每一个参数做更精细化的处理,以后再补充!


TimeWtr
1 声望0 粉丝