2017-03-23 5 views
2

任意のスライスを取ることができる関数を表現したいと思います。私はこれを行うことができると考えた:任意のスライスを取るExpress関数

some_other_fun(..)自体が interface{}型を取る
func myFunc(list []interface{}) { 
    for _, i := range list { 
    ... 
    some_other_fun(i) 
    ... 
    } 
} 

。ただし、[]DEFINITE_TYPE[]interface{}として渡すことができないため、これは機能しません。参照:https://golang.org/doc/faq#convert_slice_of_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パッケージを使用することもできますが、スライス(または配列または文字列)以外のものを渡すとパニックになるので、それは恐らく大したことではありません。

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

提供した場合は、スライスをinterfaceのスライスとして作成する必要があります。 s := []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") 
    } 
} 
関連する問題