Go可以有可选参数吗?或者我可以定义两个不同的函数,具有相同的名称和不同数量的参数?
当前回答
另一种可能是使用带有字段的结构体来指示其是否有效。来自sql的null类型,如NullString很方便。不必定义自己的类型很好,但如果你需要一个自定义数据类型,你总是可以遵循相同的模式。我认为从函数定义中可以清楚地看到可选性,并且只需要极少的额外代码或工作。
举个例子:
func Foo(bar string, baz sql.NullString){
if !baz.Valid {
baz.String = "defaultValue"
}
// the rest of the implementation
}
其他回答
你可以使用一个包含形参的结构体:
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结构体与不同的形参类型一起使用。
你可以很好地将它封装在一个类似于下面的func中。
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
fmt.Println(prompt())
}
func prompt(params ...string) string {
prompt := ": "
if len(params) > 0 {
prompt = params[0]
}
reader := bufio.NewReader(os.Stdin)
fmt.Print(prompt)
text, _ := reader.ReadString('\n')
return text
}
在这个例子中,提示符默认有一个冒号,在它前面有一个空格…
:
……但是,您可以通过向prompt函数提供参数来覆盖它。
prompt("Input here -> ")
这将导致如下提示。
Input here ->
Go中不支持可选参数和函数重载。Go确实支持可变数量的参数:参数
Go语言不支持方法重载,但你可以像可选参数一样使用可变参数,也可以使用interface{}作为参数,但这不是一个好的选择。
对于任意的、数量可能很大的可选参数,一个很好的习惯用法是使用Functional选项。
对于你的Foobar类型,首先只写一个构造函数:
func NewFoobar(options ...func(*Foobar) error) (*Foobar, error){
fb := &Foobar{}
// ... (write initializations with default values)...
for _, op := range options{
err := op(fb)
if err != nil {
return nil, err
}
}
return fb, nil
}
其中每个选项都是一个使Foobar发生突变的函数。然后为用户提供使用或创建标准选项的方便方法,例如:
func OptionReadonlyFlag(fb *Foobar) error {
fb.mutable = false
return nil
}
func OptionTemperature(t Celsius) func(*Foobar) error {
return func(fb *Foobar) error {
fb.temperature = t
return nil
}
}
操场上
为简洁起见,你可以给选项的类型命名(Playground):
type OptionFoobar func(*Foobar) error
如果需要强制参数,将它们作为构造函数的第一个参数添加到可变参数选项之前。
Functional options成语的主要好处是:
你的API可以随着时间的推移而增长,而不会破坏现有的代码,因为当需要新的选项时,构造函数签名保持不变。 它使默认用例变得最简单:根本没有参数! 它对复杂值的初始化提供了很好的控制。
这个技巧是由Rob Pike创造的,也由Dave Cheney演示过。