在Go中编写通用数据访问函数

时间:2012-08-11 12:29:51

标签: go

我正在编写允许从数据库访问数据的代码。但是,我发现自己为相似的类型和字段重复相同的代码。我怎样才能为它编写通用函数?

e.g。我想要实现的目标......

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")

2 个答案:

答案 0 :(得分:2)

所以你肯定在回归一片零接口类型的想法上走在正确的轨道上。但是,当您尝试访问特定成员或调用特定方法时,您将遇到问题,因为您不会知道您正在寻找什么类型。这是类型断言将非常方便的地方。为了扩展你的代码:

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是否为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)
        }
    }
}

(老实说,如果是我,我会做两者的混合,接受一个标准函数,但也接受字段和值字符串)

答案 1 :(得分:2)

joshlf13有一个很好的答案。虽然为了保持一些额外的类型安全性,我会稍微扩展它。而不是critera函数我会使用收集器函数。

// 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 {}切片并进行另一次转换。