2017-03-23 73 views
2

我想表達一個可以切片的功能。我認爲我可以做到這一點:其中some_other_fun(..)本身需要一個interface{}使用任意切片的Express功能

func myFunc(list []interface{}) { 
    for _, i := range list { 
    ... 
    some_other_fun(i) 
    ... 
    } 
} 

。但是,這不起作用,因爲您無法通過[]DEFINITE_TYPE作爲[]interface{}。請參閱:https://golang.org/doc/faq#convert_slice_of_interface,其中指出[] interface {}的表示方式不同。這個答案總結了爲什麼,但關於指向接口而不是接口片的指針,但原因是一樣的:Why can't I assign a *Struct to an *Interface?

上面的golang.org鏈接提供的建議建議從DEFINITE_TYPE切片重建一個新的接口切片。然而,在我想調用這個函數的代碼中,這是不切實際的(這個函數本身只能縮寫9行代碼,但這9行很常見於我們的代碼中)。

在此我想調用的功能,我將傳遞一個[]*DEFINITE_TYPE這是我的第一個想法會更容易抽象的每一種情況下,直到再次,我發現Why can't I assign a *Struct to an *Interface?(上面還掛)。此外,每次我想調用函數時,它都與DEFINITE_TYPE不同,因此爲n個類型實現n個示例並不會節省我的任何代碼行或使我的代碼更清晰(完全相反!)。

令人沮喪的是,我無法做到這一點,因爲9行在我們的代碼中是慣用的,而且錯誤類型可能很容易引入錯誤。我真的缺少泛型。真的沒有辦法做到這一點?!

回答

1

可能是做的最好的事情是定義封裝myFunc需要與片做一個接口(即,在你的榜樣,得到第n個元素)。然後,該函數的參數是該接口類型,並且爲要傳遞給該函數的每種類型定義接口方法。

你也可以用reflect包來做,但這可能不是一個好主意,因爲如果你傳遞的不是slice(或數組或字符串)以外的東西,它會驚慌失措。

func myFunc(list interface{}) { 
    listVal := reflect.ValueOf(list) 
    for i := 0; i < listVal.Len(); i++ { 
     //... 
     some_other_fun(listVal.Index(i).Interface()) 
     //... 
    } 
} 

請參閱https://play.golang.org/p/TyzT3lBEjB

3

不,沒有簡單的方法來處理它。許多人在Go中懷念泛型。

也許你可以從sort.Sort函數和sort.Interface的靈感來找到一個合理的解決方案,不需要複製切片。

3

在您提供的情況下,您必須創建您的切片,例如interfaces := []interface{}{}。在這一點上,你可以從字面上將你想要的任何類型放入切片中(甚至是混合類型)。但是,那麼你將不得不做各種類型的斷言,一切都變得非常討厭。

是常用的unmarshalers另一種技術是一個定義是這樣的:

func myFunc(list interface{}) 

由於片適合的interface,你的確可以通過正規片到這一點。您仍然需要在myFunc中執行一些驗證並鍵入斷言,但是您將對整個列表類型執行單個斷言,而不必擔心可能包含混合類型的列表。

無論哪種方式,由於是一種靜態類型的語言,您最終必須知道通過斷言傳入的類型。事情就是這樣。在你的情況下,我可能會使用上面的func簽名,然後使用類型開關來處理不同的情況。請參閱本文檔https://newfivefour.com/golang-interface-type-assertions-switch.html

所以,這樣的事情:

func myFunc(list interface{}) { 
    switch v := list.(type) { 
     case []string: 
      // do string thing 
     case []int32, []int64: 
      // do int thing 
     case []SomeCustomType: 
      // do SomeCustomType thing 
     default: 
      fmt.Println("unknown") 
    } 
}