我的目标是获取由 sql 驱动程序在其实现中反序列化的原始driver.Value
值driver.Rows.Next()
.我想处理从驱动程序返回的值到所需目标类型的转换,而不是依赖于内置于Rows.Scan
的自动转换。请注意,这个问题不会询问您对是否使用Rows.Scan
"应该"的意见。我不想使用它,我问是否有任何方法可以避免它。
一个有意义的答案根本不用Rows.Scan
。使用未知列中说明的动态方法很糟糕:它调用 Scan 的所有开销并销毁源列的类型信息,而不是将实际driver.Value
粉碎成SqlBytes
。
以下 hack 有效,但依赖于内部实现细节,该细节sql.Rows.Next()
使用我想要的未转换值填充内部字段lastcols
:
vpRows := reflect.ValueOf(rows) // rows is a *sql.Rows
vRows := reflect.Indirect(vpRows) // now we have the sql.Rows struct
mem := vRows.FieldByName("lastcols") // unexported field lastcols
unsafeLastCols := unsafe.Pointer(mem.UnsafeAddr()) // Evil
plastCols := (*[]driver.Value)(unsafeLastCols) // But effective
for rows.Next() {
rowVals := *plastCols
fmt.Println(rowVals)
}
正常的解决方案是实现自己的sql.Scanner
。 但这确实使用了rows.Scan
,所以它违反了你不使用rows.Scan
的神秘要求。
如果你真的必须避免rows.Scan
,你需要编写自己的驱动程序实现(可能包装现有的驱动程序(,它提供对driver.Value
值的访问,而无需rows.Scan
。