我想使用sql包中的Scan()
函数来执行可能(或不)返回多行的选择语句,并在我的函数中返回这些结果。
I ' m new to Golang泛型,我对如何实现这一点感到困惑。通常,我们会在*sql.Rows
上使用Scan
函数,并提供对我们希望读取行的预期"结果类型"的所有字段的引用,例如:
var alb Album
rows.Scan(&alb.ID, &alb.Title, &alb.Artist,
&alb.Price, &alb.Quantity)
,其中Album是一个结构类型,显示了这五个字段。
现在,为了不为每个SQL表编写N次类似的函数,我想使用泛型R代替。R是泛型接口类型Result,我将此类型定义为N个不同结构体中的一个:type Result interface {
StructA | StructB | StructC
}
func ExecSelect[R Result](conn *sql.DB, cmd Command, template R) []R
我怎么能现在写rows.Scan(...)
应用扫描操作对我的结构的R的具体类型的所有字段?例如,我想有rows.Scan(&res.Field1, &res.Field2, ...)
的res是R类型,扫描应该接收我当前的具体类型R的所有字段。我是否真的需要提供一个"模板"作为R的具体类型的参数,以便在运行时它变得清晰哪个结构现在是相关的?
请纠正我在考虑泛型时所犯的任何错误。
这是一个糟糕的泛型用例。
函数sql.Rows.Scan
的参数应该是扫描目的地,即你的结构字段,结果集中每列一个,在泛型函数体内,你不能访问R
类型参数的字段。
即使你这样做,在你的Result
约束结构可能有不同的字段…?那么你如何设想写泛型与不同的一起工作的代码字段?
您可以通过提供任意结构体扫描(如sqlx
)和StructScan
等功能的包来完成您想要的功能,但是它在底层使用反射将结构体字段映射到sql.Rows.Scan
参数,因此使用泛型根本没有获得任何好处。
如果有的话,你正在使它变得更糟,因为现在你有了使用类型参数的额外性能开销。