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

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

于 2012-08-12T00:53:37.553 回答