2013-11-22 62 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時,因爲特殊構造函數的數量增加了組合。 –