2014-08-30 35 views
1

鑑於以下結構Foo和處理多種類型的目標(其中Handle可能是Read,Write等)。我明白,當我們使用空的界面時,我們會失去編譯時類型檢查,但除此之外,每個類型的優缺點是什麼?最後,實現這個目標的最習慣的方式是什麼?一種功能開啓的類型vs許多類型的功能

package main 

type Foo struct { 
    A int 
    B string 
} 

//Handle all types with switch 
func (f *Foo) Handle(obj interface{}) { 

    switch obj := obj.(type) { 
    case int: 
     //do int stuff... 
     f.A + obj 
    case string: 
     //do string stuff... 
     f.B + obj 
    default: 
     panic("Unknown type") 
    } 
} 

//Handle each type individually 
func (f *Foo) HandleInt(i int) { 
    //do int stuff... 
    f.A + i 
} 
func (f *Foo) HandleString(s string) { 
    //do string stuff... 
    f.B + s 
} 

回答

2

如果您要通過reflect處理用戶定義的類型,則需要空接口。這是fmt.Printf,json.Encodebinary.Write接受它的理由。根據你之前發佈的Merkle tree scenario,你在散列的東西,如果你的Hash()有一個基於reflect的回退來散列用戶創建的結構,你會使用一個空的接口。

如果您只打算爲幾種關鍵類型提供方法([]byte,string,無論什麼),具體方法可能更有意義。除了編譯時檢查外,函數列表還可以作爲您可以散列的文檔。另一方面,如果有像你想要散列的十幾種類型 - 考慮所有(u)int類型和它們的片段 - 我想我會使用interface{}只是爲了整潔的API,除非你絕對需要最好的表現,但我認爲這種或那種方式沒有明確的共識。

+0

是的,[u] int類型的數量實際上讓我感到困擾。我並不期待每個內置類型都有一個方法。美學上,我寧願有一種方法並記錄下來。此外,可能包括3種特定方法和1種通用方法(兩種方法)都會混淆用戶。 – jpillora 2014-08-30 07:14:11

1

一個很好的例子是package sortsources here),其中:

  • 確實實現了基本類型的一種方法(如你的第二個方法)
  • 提出了一種interface的類型被排序必須執行。
  • 可以使用聲明的方法。如果你Handle(obj interface{}) =>Handle(obj Interface)做同樣的排序切片和用戶定義的集合

,這將幫助你處理(用於更復雜的類型)定義一次,「 Interface'。
滿足所述Interface的任何類型將被傳遞給通用Handle()函數。
而且您可以處理切片(類似於this example for sort)或使用定義的集合。

+0

感謝您的例子 - 這是一個很好的模式,但我希望能夠處理內置類型(所有類型的[u]整數),所以我想我會用@ twotwotwo的答案。 – jpillora 2014-08-30 07:15:39