Go可以有可选参数吗?或者我可以定义两个不同的函数,具有相同的名称和不同数量的参数?
当前回答
你可以使用一个包含形参的结构体:
type Params struct {
a, b, c int
}
func doIt(p Params) int {
return p.a + p.b + p.c
}
// you can call it without specifying all parameters
doIt(Params{a: 1, c: 9})
与省略号(params…SomeType)相比,其主要优点是可以将param结构体与不同的形参类型一起使用。
其他回答
所以我觉得我来这个派对已经晚了,但我一直在寻找是否有比我现在做的更好的方法。这在某种程度上解决了你试图做的事情,同时也给出了一个可选参数的概念。
package main
import "fmt"
type FooOpts struct {
// optional arguments
Value string
}
func NewFoo(mandatory string) {
NewFooWithOpts(mandatory, &FooOpts{})
}
func NewFooWithOpts(mandatory string, opts *FooOpts) {
if (&opts) != nil {
fmt.Println("Hello " + opts.Value)
} else {
fmt.Println("Hello")
}
}
func main() {
NewFoo("make it work please")
NewFooWithOpts("Make it work please", &FooOpts{Value: " World"})
}
更新1:
添加了一个功能示例,以显示功能与示例的对比
我最终使用了参数和可变参数结构的组合。这样,我就不需要改变现有的由多个服务使用的接口,而且我的服务能够根据需要传递额外的参数。golang playground中的示例代码:https://play.golang.org/p/G668FA97Nu
Go不支持可选参数、默认值和函数重载,但你可以使用一些技巧来实现相同的功能。
分享一个例子,你可以在一个函数中有不同数量和类型的参数。这是一个简单易懂的代码,你需要添加错误处理和一些逻辑。
func student(StudentDetails ...interface{}) (name string, age int, area string) {
age = 10 //Here Age and area are optional params set to default values
area = "HillView Singapore"
for index, val := range StudentDetails {
switch index {
case 0: //the first mandatory param
name, _ = val.(string)
case 1: // age is optional param
age, _ = val.(int)
case 2: //area is optional param
area, _ = val.(string)
}
}
return
}
func main() {
fmt.Println(student("Aayansh"))
fmt.Println(student("Aayansh", 11))
fmt.Println(student("Aayansh", 15, "Bukit Gombak, Singapore"))
}
我有点晚了,但如果你喜欢流畅的界面,你可能会为链式调用设计你的setter:
type myType struct {
s string
a, b int
}
func New(s string, err *error) *myType {
if s == "" {
*err = errors.New(
"Mandatory argument `s` must not be empty!")
}
return &myType{s: s}
}
func (this *myType) setA (a int, err *error) *myType {
if *err == nil {
if a == 42 {
*err = errors.New("42 is not the answer!")
} else {
this.a = a
}
}
return this
}
func (this *myType) setB (b int, _ *error) *myType {
this.b = b
return this
}
然后像这样调用它:
func main() {
var err error = nil
instance :=
New("hello", &err).
setA(1, &err).
setB(2, &err)
if err != nil {
fmt.Println("Failed: ", err)
} else {
fmt.Println(instance)
}
}
这类似于@Ripounet回答中给出的函数选项习惯用法,具有相同的好处,但有一些缺点:
如果发生错误,它不会立即中止,因此,如果您希望构造函数经常报告错误,那么它的效率会稍微低一些。 您将不得不花费一行时间声明一个err变量并将其归零。
然而,有一个可能的小优势,这种类型的函数调用应该更容易为编译器内联,但我真的不是一个专家。
您可以通过映射传递任意命名参数。如果参数具有不一致的类型,则必须使用“aType = map[key].(*foo.type)”断言类型。
type varArgs map[string]interface{}
func myFunc(args varArgs) {
arg1 := "default"
if val, ok := args["arg1"]; ok {
arg1 = val.(string)
}
arg2 := 123
if val, ok := args["arg2"]; ok {
arg2 = val.(int)
}
fmt.Println(arg1, arg2)
}
func Test_test() {
myFunc(varArgs{"arg1": "value", "arg2": 1234})
}