2013-11-22 63 views
2

,我发现自己使用下面的模式作为一种可选的参数,以获得可选参数与围棋结构构造函数的默认值:在围棋结构构造默认

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

有什么问题:http://play.golang.org/p/DYw5pWzRQC? 更少的代码,更好的理解,更通用... 上面看起来像一个等待问题的解决方案... – metakeule

+0

目前,我正在使用这种模式来创建测试中的灯具。恕我直言,明确分配默认值不会使这些测试更易于理解或更具可读性。 –

回答

2

该方法对我来说似乎是合理的。但是,你有一个错误。如果我明确地将Type设置为0,它将会get switched to 1

我建议的修复方法:使用文字为默认值的结构:http://play.golang.org/p/KDNUauy6Ie

或许提取出来:http://play.golang.org/p/QpY2Ymze3b

+0

但是现在获得Type的默认值的唯一方法是不向NewObject传递任何对象。 NewObject(&Object {Name:“foo”})将返回一个类型为0的对象。我想我宁愿不允许Type 0。如果你需要类型0,你可以在调用构造函数之后在返回的对象上设置它。 –

1

你可以使用...操作。

,而不是写ToCall(A = B)如同在Python编写,ToCall( “A”,B)

Go Play Example

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{}) 

} 
+0

注意这在其他地方可见,例如大猩猩网络工具包。 – Crisfole

+0

这要求ToCall键入断言(可能会在运行时失败)并对ToCall进行重大修改以允许默认参数。这是一个有趣的例子,说明如何伪造关键字参数,但我认为它不能回答我的问题。 –

1

"Allocation with new" in Effective Go看看。他们解释了使零价值结构成为有用的默认值。

如果您可以让Object.Type(和您的其他字段)的默认值为零,那么Go结构文字已经完全提供了您请求的功能。

从节上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以零默认值,不需要任何代码的上述变化,因为所有的结构文字使用标记初始化。这就派上用场了。

+0

使用结构字段的零值有时可能并且直观,但并非总是如此,不幸的是我的情况并非如此。我认为有必要创建专门的构造函数,比如你的NewFooObject,当需要非零默认值的字段数很少时,而不是当字段数大于2时,因为特殊构造函数的数量增加了组合。 –