我发现自己使用以下模式作为在Go结构构造函数中使用默认值获取可选参数的方法:
package main
import (
"fmt"
)
type Object struct {
Type int
Name string
}
func NewObject(obj *Object) *Object {
if obj == nil {
obj = &Object{}
}
// Type has a default of 1
if obj.Type == 0 {
obj.Type = 1
}
return obj
}
func main() {
// create object with Name="foo" and Type=1
obj1 := NewObject(&Object{Name: "foo"})
fmt.Println(obj1)
// create object with Name="" and Type=1
obj2 := NewObject(nil)
fmt.Println(obj2)
// create object with Name="bar" and Type=2
obj3 := NewObject(&Object{Type: 2, Name: "foo"})
fmt.Println(obj3)
}
是否有更好的方法允许使用默认值的可选参数?
答案 0 :(得分:2)
这种方法对我来说似乎是合理的。但是,你有一个错误。如果我明确将Type
设置为0,则会get switched to 1。
我建议的修复:使用结构文字作为默认值:http://play.golang.org/p/KDNUauy6Ie
或者可能将其摘录出来:http://play.golang.org/p/QpY2Ymze3b
答案 1 :(得分:1)
您可以使用...运算符。
而不是像你写的python中那样编写ToCall(a = b),ToCall(“a”,b)
func GetKwds(kwds []interface{}) map[string]interface{} {
result := make(map[string]interface{})
for i := 0; i < len(kwds); i += 2 {
result[kwds[i].(string)] = kwds[i+1]
}
return result
}
func ToCall(kwds ...interface{}) {
args := GetKwds(kwds)
if value, ok := args["key"]; ok {
fmt.Printf("key: %#v\n", value)
}
if value, ok := args["other"]; ok {
fmt.Printf("other: %#v\n", value)
}
}
func main() {
ToCall()
ToCall("other", &map[string]string{})
ToCall("key", "Test", "other", &Object{})
}
答案 2 :(得分:1)
看看"Allocation with new" in Effective Go。他们解释了使零值结构成为一个有用的默认值。
如果您可以使Object.Type
(以及您的其他字段)的默认值为零,那么Go struct literals已经为您提供了您正在请求的功能。
来自composite literals的部分:
复合文字的字段按顺序排列,并且必须全部存在。但是,通过将元素明确标记为字段:值对,初始值设定项可以按任何顺序显示,并将缺失的元素保留为各自的零值。
这意味着您可以替换它:
obj1 := NewObject(&Object{Name: "foo"})
obj2 := NewObject(nil)
obj3 := NewObject(&Object{Type: 2, Name: "foo"})
用这个:
obj1 := &Object{Name: "foo"}
obj2 := &Object{}
obj3 := &Object{Type: 2, Name: "foo"}
如果无法将零值设为所有字段的默认值,则为recommended approach is a constructor function。例如:
func NewObject(typ int, name string) *Object {
return &Object{Type: typ, Name: name}
}
如果希望Type
具有非零默认值,则可以添加另一个构造函数。假设Foo
个对象是默认对象,并且Type
为1。
func NewFooObject(name string) *Object {
return &Object{Type: 1, Name: name}
}
您只需为您使用的每组非零默认值创建一个构造函数。您总是可以通过将某些字段的语义更改为默认值为零来减少该设置。
另外,请注意,使用零默认值向Object
添加新字段不需要上面的任何代码更改,因为所有结构文字都使用标记初始化。这就派上用场了。
答案 3 :(得分:0)
https://play.golang.org/p/SABkY9dbCOD
这里是使用对象的方法设置默认值的替代方法。我发现它很有用,尽管它与您所使用的并没有太大区别。如果它是软件包的一部分,则可以更好地使用它。我并没有声称自己是围棋专家,也许您会提供一些额外的建议。
package main
import (
"fmt"
)
type defaultObj struct {
Name string
Zipcode int
Longitude float64
}
func (obj *defaultObj) populateObjDefaults() {
if obj.Name == "" {
obj.Name = "Named Default"
}
if obj.Zipcode == 0 {
obj.Zipcode = 12345
}
if obj.Longitude == 0 {
obj.Longitude = 987654321
}
}
func main() {
testdef := defaultObj{Name: "Mr. Fred"}
testdef.populateObjDefaults()
fmt.Println(testdef)
testdef2 := defaultObj{Zipcode: 90210}
testdef2.populateObjDefaults()
fmt.Println(testdef2)
testdef2.Name = "Mrs. Fred"
fmt.Println(testdef2)
testdef3 := defaultObj{}
fmt.Println(testdef3)
testdef3.populateObjDefaults()
fmt.Println(testdef3)
}
输出:
{Mr. Fred 12345 9.87654321e+08}
{Named Default 90210 9.87654321e+08}
{Mrs. Fred 90210 9.87654321e+08}
{ 0 0}
{Named Default 12345 9.87654321e+08}
答案 4 :(得分:0)
Dave Cheney为此提供了一个不错的解决方案,您可以使用功能选项来覆盖默认值:
https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
因此您的代码将变为:
package main
import (
"fmt"
)
type Object struct {
Type int
Name string
}
func NewObject(options ...func(*Object)) *Object {
// Setup object with defaults
obj := &Object{Type: 1}
// Apply options if there are any
for _, option := range options {
option(obj)
}
return obj
}
func WithName(name string) func(*Object) {
return func(obj *Object) {
obj.Name = name
}
}
func WithType(newType int) func(*Object) {
return func(obj *Object) {
obj.Type = newType
}
}
func main() {
// create object with Name="foo" and Type=1
obj1 := NewObject(WithName("foo"))
fmt.Println(obj1)
// create object with Name="" and Type=1
obj2 := NewObject()
fmt.Println(obj2)
// create object with Name="bar" and Type=2
obj3 := NewObject(WithType(2), WithName("foo"))
fmt.Println(obj3)
}