如何从嵌套接口中获取值
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
}
values
和 args
切片可以逐行重复使用。
在循环外分配 values
和 args
以减少内存压力。
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
}
我在尝试使用 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
}
values
和 args
切片可以逐行重复使用。
在循环外分配 values
和 args
以减少内存压力。
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
}