在日常的Go程序开发中,函数(办法)参数的传递是必不可少的一部分,如果参数比拟少,能够在办法参数局部间接列出,如果参数很多,可不可以一个一个列举呢,答案是能够的。然而这种形式存在两个问题:
- 参数很多,列举进去之后办法的参数局部会很长,不美观;
每一个参数都有对应的数据类型,太多的参数在函数(办法)调用的时候容易写错程序;
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) errorfunc 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 }}
至此,办法参数传递和可选参数就实现,以上的四种形式能够满足大部分场景了。至于每一个参数做更精细化的解决,当前再补充!