You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang REST API查询返回嵌套Struct重复最后一行数据问题

问题根源:循环复用同一个指针结构体实例

你遇到的问题核心是在循环外部定义了Config变量c,并且Data是指针类型,导致所有切片里的Config对象共享同一个Data指针,最终所有条目都显示最后一次反序列化的Data内容。

具体来说:

  • 你在List函数开头就定义了var c Config,这个变量在整个循环过程中是同一个实例。
  • 第一次循环时,json.Unmarshal会为c.Data分配一块内存并写入数据;后续循环时,Unmarshal不会重新分配新的内存,而是直接把新的JSON数据覆盖到之前那块内存里。
  • 因为切片configs里每次append的都是c的副本,但c.Data是指针,副本的指针依然指向同一块内存,所以最终所有Config的Data都指向最后一次写入的内容。
修复方案

有两种简单的修复方式,选一种就行:

方案1:在循环内部定义Config变量

把var c Config移到for rows.Next()循环内部,这样每次循环都会创建一个全新的Config实例,Data指针也会指向新的内存:

func List(db *sql.DB, start, count int) ([]Config, error) {
    var dt string
    rows, err := db.Query(
        "SELECT * FROM configs LIMIT $1 OFFSET $2", count, start)
    if err != nil {
        return nil, err
    }
    defer rows.Close()
    configs := []Config{}
    for rows.Next() {
        var c Config // 移到循环内,每次都是新实例
        if err := rows.Scan(&c.ID, &c.Name, &dt); err != nil {
            return nil, err
        }
        // 处理Unmarshal的错误,避免静默失败
        if err := json.Unmarshal([]byte(dt), &c.Data); err != nil {
            return nil, err
        }
        configs = append(configs, c)
    }
    // 检查循环过程中是否出现错误
    if err := rows.Err(); err != nil {
        return nil, err
    }
    return configs, nil
}

方案2:每次循环前重置Data指针

如果不想移动变量定义,可以在每次循环时重置c的所有字段,确保Unmarshal会写入新的内存:

func List(db *sql.DB, start, count int) ([]Config, error) {
    var dt string
    var c Config
    rows, err := db.Query(
        "SELECT * FROM configs LIMIT $1 OFFSET $2", count, start)
    if err != nil {
        return nil, err
    }
    defer rows.Close()
    configs := []Config{}
    for rows.Next() {
        c = Config{} // 重置所有字段,清空上一次的残留数据
        if err := rows.Scan(&c.ID, &c.Name, &dt); err != nil {
            return nil, err
        }
        if err := json.Unmarshal([]byte(dt), &c.Data); err != nil {
            return nil, err
        }
        configs = append(configs, c)
    }
    if err := rows.Err(); err != nil {
        return nil, err
    }
    return configs, nil
}
额外建议
  • 永远不要忽略json.Unmarshal的错误!你原来的代码里没有处理这个错误,如果数据库里的dt字段是无效JSON,会导致静默失败,后续排查问题很麻烦。
  • 循环结束后一定要检查rows.Err(),它会返回循环过程中出现的错误(比如IO错误),避免漏掉潜在问题。

内容的提问来源于stack exchange,提问作者learner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:40:06