
本文详解如何通过 for 循环(尤其是配合 database/sql 的 rows.next())将查询结果逐条扫描并填充到自定义结构体切片中,涵盖标准用法、字段映射要点、内存安全注意事项及完整可运行示例。
本文详解如何通过 for 循环(尤其是配合 database/sql 的 rows.next())将查询结果逐条扫描并填充到自定义结构体切片中,涵盖标准用法、字段映射要点、内存安全注意事项及完整可运行示例。
在 Go 中,“填充对象”通常指将外部数据(如数据库查询结果、API 响应或用户输入)批量加载到结构体切片中。以 Rows 类型为例——它是 []Row 的类型别名,而 Row 包含 Name、Completed、Due 和 Rcount 四个字段。静态初始化(如 todos := Rows{Row{Name: "Write presentation"}, ...})适用于测试或固定数据;但生产环境中,我们更常从数据库动态填充。
✅ 标准动态填充模式(基于 database/sql)
最典型场景是从 SQL 查询中读取多行记录,并逐条扫描进 Row 实例:
rows, err := db.Query("SELECT name, completed, due, rcount FROM todos WHERE active = ?", true)
if err != nil {
log.Fatal("Query failed:", err)
}
defer rows.Close()
var todos Rows // 即 []Row
for rows.Next() {
var r Row
// 注意:Scan 参数顺序必须与 SELECT 字段顺序严格一致,且传入地址
if err := rows.Scan(&r.Name, &r.Completed, &r.Due, &r.Rcount); err != nil {
log.Printf("Scan error: %v", err)
continue // 或 break,视错误策略而定
}
todos = append(todos, r)
}
// 检查 rows.Next() 之后的潜在错误(如列类型不匹配)
if err := rows.Err(); err != nil {
log.Fatal("Rows iteration error:", err)
}⚠️ 关键注意事项
- 字段顺序必须匹配:Scan() 的参数顺序需与 SQL SELECT 子句中字段顺序完全一致,否则会静默赋值错位。
- 使用地址符 &:Scan 要求传入变量地址,漏写 & 将导致 panic(sql: expected pointer)。
- 显式调用 rows.Close():避免连接泄漏;推荐用 defer 确保执行。
- 检查 rows.Err():rows.Next() 返回 false 后,仍需检查 rows.Err() 判断是否因扫描错误提前终止。
- 避免重复分配:若预估数据量,可用 make([]Row, 0, expectedCount) 初始化切片,提升 append 性能。
✅ 更健壮的写法(带错误处理与类型安全)
对于高可靠性场景,建议封装为可复用函数:
func QueryTodos(db *sql.DB) (Rows, error) {
rows, err := db.Query(`SELECT name, completed, due, rcount FROM todos`)
if err != nil {
return nil, fmt.Errorf("query todos: %w", err)
}
defer rows.Close()
var todos Rows
for rows.Next() {
var r Row
if err := rows.Scan(&r.Name, &r.Completed, &r.Due, &r.Rcount); err != nil {
return nil, fmt.Errorf("scan row: %w", err)
}
todos = append(todos, r)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("iterate rows: %w", err)
}
return todos, nil
}? 提示:若数据库字段名与 Go 字段名不一致(如 due_date → Due),可在结构体字段上使用 db tag 配合第三方库(如 sqlx)实现自动映射,但原生 database/sql 不支持该特性,必须手动按序 Scan。
掌握这一模式,即可安全、高效地将任意来源的结构化数据批量载入 Go 对象,是构建数据层的基础能力。

















