前言
最近在使用golang 开发时常会碰到一个函数传参问题,就是在使用工厂模式初始化结构体时可能有些字段可传可不传,那我到底该不该把这个字段在函数中初始化呢,所以到底我们应该怎么传呢?
一、interface
可能绝大部分人第一时间想到的就是使用 interface不确定数据类型去实现。效果如下:
type Person struct {
Name string
Age int
}
func NewPerson(args ...interface{}) *Person {
p := new(Person)
for _, arg := range args {
switch arg.(type) {
case string:
p.Name=arg.(string)
case int:
p.Age=arg.(int)
}
}
return p
}
当然这也是一种方法,但是有些时候使用者并不知道需要传什么类型,传什么数据,而且当结构体中的数据类型一致时我们就不知道该怎么去赋值了,所以这类方法也是有点不适当的地方。
二、struct当然你也可以直接穿一个Person结构体,那这跟你直接new 一个person 结构体有啥区别呢,所以并不是很推荐传入结构体。
三、func(最优解)既然golang中函数是一等公民的话咱们需要充分利用起来。
// 定义一个函数类型的type
type Option func(person *Person)
// 初始化Person 此时我们入参就不是interface了,而是上面定义的Option
func NewPerson(opts ...Option) *Person {
p := new(Person)
for _, f := range opts {
f(p)
}
return p
}
定义结构体字段的 Option 方法
// WithName ...
func WithName(name string) Option {
return func(opt *Person) {
opt.Name = name
}
}
// WithAge ...
func WithAge(age int) Option {
return func(opt *Person) {
opt.Age = age
}
}
当我们使用时想要初始化啥字段我们就直接传入相应的Option方法就行;而且也不用考虑参数个数,参数类型;代码如下:
func main() {
person := NewPerson(
WithName("张三"),
WithAge(11),
)
fmt.Printf("%+v", person) //&{Name:张三 Age:11}
}
此方法是不是让调用者一眼就能看明白,当然开发者需要加字段的话也很简单,只需添加相应的Option方法就行。所以这里还是非常推荐这种方法的。在很多开源项目中也能看到这种模式的身影
总结
看完以上三种方法你是否对golang 的不确定参数的传值到底该怎么传有了答案呢,最后强烈推荐大家使用 第三种方法 使用函数作为参数去 初始化结构体。