思路
在 Python 中,定义函数时可以给出部分参数的默认值以及变长关键字参数:
class Work:
def Run(self, identity, name='Jack', gender=True, age=12, **others):
...
其中参数 other
的返回类型为字典(dict
)。
然而 Go 中不使用参数默认值。
希望在 Go 中实现形同如下 Python 语句的传参方式:
work.Run('manager', name='Mike', gender=True, married=False)
并为未接受传递的参数提供默认值。
不妨将所有可选参数以映射(map
)的形式储存于函数内。
一般地,对于一个工作实例:
type Work struct {
identity string
name string
gender bool
age int
}
为其绑定一个带有变长参数的方法,并在内部指定参数默认值:
func (work *Work) Run(identity string, others ...interface{}) {
options := map[string]interface{}{
"name": "Jack",
"gender": true,
}
}
此时,可以如此传参调用:
func main() {
work := new(Work)
work.Run("manager", 1, 2, 3)
}
为使 others
数组中的数据覆盖 options
,需要以「键值对」的形式传入每个参数。
为此,可以定义并使用 struct
实例:
type Option struct {
name string
value interface{}
}
在函数中解析数组 Option
,以其中数据覆盖映射 options
:
func (work *Work) Run(identity string, others ...Option) {
options := map[string]interface{}{
"name": "Jack",
"gender": true,
}
for _, other := range others {
options[other.name] = other.value
}
// 如有需要,可按如下方式设置属性值:
work.identity = identity
work.name = optionSet["name"].(string)
work.gender = optionSet["gender"].(bool)
work.age = optionSet["age"].(int)
}
并通过如下形式调用函数:
work.Run(
"manager",
Option{"name": "Mike"},
Option{"gender": true},
Option{"age": 7},
)
至此,前文所述的工作经已完成。
进阶
为使代码更加简洁优雅,可以为参数列表 - 映射 options
定义类型:
type Options map[string]interface{}
尔后,options
的初始化语句应修改为:
options := Options{
"name": "Jack",
"gender": true,
}
为结构体 Option
建立构造方法 With
:
func With(name string, value interface{}) Option {
return Option{name, value}
}
此时,可以通过如下形式传递参数及调用函数:
work.Run(
"manager",
With("name", "Mike"),
With("gender", true),
With("age", 7),
)
map
是引用类型,故而可将之传入函数以对其赋值,无需使用指针变量。
定义绑定于结构体 Option
的 AddTo
方法:
func (option *Option) AddTo(options Options) {
options[option.name] = option.value
}
将函数 Run
内为 options
赋值的语句修改为:
for _, other := range others {
other.AddTo(options)
}
最后,可将 Option
、Options
、AddTo
、With
封装以广泛使用。
完整代码
package main
import "fmt"
type Option struct {
name string
value interface{}
}
func With(name string, value interface{}) Option {
return Option{name, value}
}
type Options map[string]interface{}
func (option *Option) add(options Options) {
options[option.name] = option.value
}
type Work struct {
identity string
name string
gender bool
age int
}
func (work *Work) Run(identity string, others ...Option) {
options := Options{
"name": "Jack",
"gender": true,
}
for _, other := range others {
other.AddTo(options)
}
work.identity = identity
work.name = options["name"].(string)
work.gender = options["gender"].(bool)
work.age = options["age"].(int)
fmt.Printf("%+v\n%+v", options, *work)
}
func main() {
work := new(Work)
work.Run(
"manager",
With("name", "Mike"),
With("gender", true),
With("age", 7),
)
}
控制台输出:
map[age:7 gender:true name:Mike]
{identity:manager name:Mike gender:true age:7}