2

データベースからのデータアクセスを可能にするコードを書いています。ただし、同じようなタイプとフィールドに対して同じコードを繰り返していることに気付きました。同じもののジェネリック関数をどのように書くことができますか?

例えば、私が達成したいこと...

type Person{FirstName string}
type Company{Industry string}

getItems(typ string, field string, val string) ([]interface{}) {
    ...
}

var persons []Person
persons = getItems("Person", "FirstName", "John")

var companies []Company
cs = getItems("Company", "Industry", "Software")
4

2 に答える 2

2

joshlf13 には素晴らしい答えがあります。ただし、追加の型の安全性を維持するために、少し拡張します。基準関数の代わりに、コレクター関数を使用します。

// typed output array no interfaces
output := []string{}

// collector that populates our output array as needed
func collect(i interface{}) {
 // The only non typesafe part of the program is limited to this function
 if val, ok := i.(string); ok {
   output = append(output, val) 
 }
}

// getItem uses the collector  
func getItem(collect func(interface{})) {
    foreach _, item := range database {
        collect(item)
    }
}

getItem(collect) // perform our get and populate the output array from above.

これには、getItems の呼び出し後に interface{} スライスをループして、さらに別のキャストを行う必要がないという利点があります。

于 2012-08-12T03:50:18.010 に答える
2

したがって、nil インターフェイス タイプのスライスを返すという考えは、間違いなく正しい方向に進んでいます。ただし、特定のメンバーにアクセスしたり、特定のメソッドを呼び出したりしようとすると、探している型がわからないため、問題が発生します。ここで、型アサーションが非常に便利になります。コードを少し拡張するには:

getPerson(typ string, field string, val string) []Person {
    slice := getItems(typ, field, val)
    output := make([]Person, 0)
    i := 0
    for _, item := range slice {
        // Type assertion!
        thing, ok := item.(Person)
        if ok {
            output = append(output, thing)
            i++
        }
    }
    return output
}

つまり、一般的な検索を実行し、正しいタイプのアイテムのみを除外します。具体的には、型アサーション:

thing, ok := item.(Person)

item変数が typeであるかどうかを確認しPerson、そうであれば値と true を返し、そうでなければ nil と false を返します (したがって、ok をチェックすると、アサーションが成功したかどうかがわかります)。

実際には、必要に応じて、これをさらに一歩進めて、getItems()別のブール関数で関数を定義できます。基本的にはgetItems()、関数を実行してデータベース内の各要素に渡し、要素で関数を実行して true が返された場合にのみ、その要素を結果に追加するという考え方です。

getItem(critera func(interface{})bool) []interface{} {
    output := make([]interface{}, 0)
    foreach _, item := range database {
        if criteria(item) {
            output = append(output, item)
        }
    }
}

(正直なところ、もしそれが私だったら、条件関数を受け入れるだけでなく、フィールドと値の文字列も受け入れる2つのハイブリッドを行うでしょう)

于 2012-08-12T00:53:37.553 に答える