如何从嵌套接口中获取值

How to get value from nested interface

我在尝试使用 odbc 且不使用 ORM 从我的数据库中动态读取字符串时遇到了一个小问题。

也许值得一提的是,使用另一个 SQL 服务器驱动程序,我收到的数据是字符串形式的,而不是 []uint8 ,它解决了我的问题)。

我正在使用以下代码将一行扫描到切片数组中:

func createEmptyResultSet(numOfCols int) []interface{} {
res := make([]interface{}, numOfCols)
for col := 0; col < numOfCols; col++ {
    var i interface{}
    res[col] = &i
}
return res

} 和实际扫描:

func rowsToStringInterfaceMapSlice(rows *sql.Rows, cols []string) ([]map[string]interface{}, error) {
    var err error
    rowsRes := make([]map[string]interface{}, 0)
    numOfCols := len(cols)
    for rows.Next() {
        row := make(map[string]interface{}, numOfCols)
        values := createEmptyResultSet( numOfCols)
        if rows.Scan(values...); err != nil {
            return nil, err
        }
        rowsRes = append(rowsRes, row)
    }
    return rowsRes, nil
}

我正在尝试访问以下切片:

使用以下代码的几个版本:

  for i := range values {
//also tried multiple get value
                t := reflect.TypeOf(values[i])
                if t.Kind() == reflect.Slice {
                    row[cols[i]] = interfaceSliceToString(values[i])
                } else {
                    row[cols[i]] = values[i]
                }
            }

但似乎没有任何效果。 有什么建议吗?

values 中的值的类型为 *interface{}。切片的测试永远不会成功。

使用下面的函数来简化事情。此函数 returns 一片值和一片指向值的指针。使用第一个切片 用于访问值和第二个切片作为扫描的可变参数。

func createEmptyResultSet(numOfCols int) (values []interface{}, args []interface{}) {
    values = make([]interface{}, numOfCols)
    args = make([]interface{}, numOfCols)
    for col := 0; col < numOfCols; col++ {
        args[col] = &values[col]
    }
    return
}

这样使用:

    values, args := createEmptyResultSet( numOfCols)
    if rows.Scan(args...); err != nil {
        return nil, err
    }

现在 values 包含实际值而不是指向值的指针。

使用类型断言而不是反射来查找 []byte 值。

for i, v := range values {
   switch v := v.(type) {
   case []byte:
      row[cols[i]] = string(v)
   default:
      row[cols[i]] = v
   }
}

这是 rowsToStringInterfaceMapSlice 的完整代码:

func rowsToStringInterfaceMapSlice(rows *sql.Rows, cols []string) ([]map[string]interface{}, error) {
    var err error
    rowsRes := make([]map[string]interface{}, 0)
    numOfCols := len(cols)
    for rows.Next() {
        row := make(map[string]interface{}, numOfCols)
        values, args := createEmptyResultSet( numOfCols)
        if rows.Scan(args...); err != nil {
            return nil, err
        }
        for i, v := range values {
           switch v := v.(type) {
           case []byte:
              row[cols[i]] = string(v)
           default:
              row[cols[i]] = v
           }
        }
        rowsRes = append(rowsRes, row)
    }
    return rowsRes, nil
}

valuesargs 切片可以逐行重复使用。 在循环外分配 valuesargs 以减少内存压力。

func rowsToStringInterfaceMapSlice(rows *sql.Rows, cols []string) ([]map[string]interface{}, error) {
    rowsRes := make([]map[string]interface{}, 0)
    values, args := createEmptyResultSet(len(cols))
    for rows.Next() {
        row := make(map[string]interface{}, len(cols))
        for i := range values {
            values[i] = nil
        }
        if err := rows.Scan(args...); err != nil {
            return nil, err
        }
        for i, v := range values {
            switch v := v.(type) {
            case []byte:
                row[cols[i]] = string(v)
            default:
                row[cols[i]] = v
            }
        }
        rowsRes = append(rowsRes, row)
    }
    return rowsRes, nil
}