填充作为参数指定的接口类型的一部分(例如,为数据库/ sql实现ScanAll)

时间:2018-11-05 18:15:05

标签: go

我们如何实现一个函数,该函数将返回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实际需要做的工作看起来并没有什么不同...

1 个答案:

答案 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
}

此代码也应与支持将多列扫描到结构的数据库包一起使用。

相关问题