我们如何实现一个函数,该函数将返回SQL查询产生的所有行并将它们转换为接口数组的dest
(可能不能用作Scan
)?
我假设目标数组必须作为函数的参数给出。但是然后,我仍然不知道应该如何完成实施:
func GetAll(query string, dest interface{}) error {
rows, err := s.db.Query(query)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var destRow ??? /* do not have a type. using reflect.TypeOf(dest).Elem()? */
err := rows.Scan(&destRow)
if err != nil {
return err
}
dest = append(dest, destRow) /* would even compile? */
}
return nil
}
与json.Unmarshal
实际需要做的工作看起来并没有什么不同...
答案 0 :(得分:1)
这是使用reflect package的解决方案。使用指向切片的指针调用该函数。
func GetAll(query string, dest interface{}) error {
// Return error if dest is not a pointer to a slice.
slice := reflect.ValueOf(dest)
if slice.Kind() != reflect.Ptr {
return errors.New("dest must be pointer")
}
slice = slice.Elem()
if slice.Kind() != reflect.Slice {
return errors.New("dest must be pointer to struct")
}
rows, err := db.Query(query)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
// Create a new slice element. The variable elementp holds a
// pointer to the new element.
elementp := reflect.New(slice.Type().Elem())
err := rows.Scan(elementp.Interface())
if err != nil {
return err
}
// Append the element to the slice.
slice.Set(reflect.Append(slice, elementp.Elem()))
}
return nil
}
当查询结果只有一列并且dest是指向适合该列的类型的切片的指针时,以上代码可与标准数据库/ sql包一起使用。这是一个示例:
var names []string
if err := GetAll(db, "select name from people", &names); err != nil {
// handle error
}
此代码也应与支持将多列扫描到结构的数据库包一起使用。