【问题标题】:How to avoid slice reference to the same memory block如何避免对同一内存块的切片引用
【发布时间】:2015-10-30 12:17:40
【问题描述】:

从数据库查询并尝试插入切片时遇到问题(包含一些地图[字符串]接口{}) 即使我已经使用 make 创建了一个新的内存块,切片似乎总是映射到同一个内存块。

type DBResult []map[string]interface{}

func ResultRows(rows *sql.Rows, limit int) (DBResult, error) {
    cols, err := rows.Columns()
    if err != nil {
        return nil, err
    }

    vals := make([]sql.RawBytes, len(cols))
    scanArgs := make([]interface{}, len(vals))
    for i := range vals {
        scanArgs[i] = &vals[i]
    }

    if limit > QUERY_HARD_LIMIT {
        limit = QUERY_HARD_LIMIT
    }

    res := make(DBResult, 0, limit)
    for rows.Next() {
        err = rows.Scan(scanArgs...)
        m := make(map[string]interface{})

        for i := range vals {
            m[cols[i]] = vals[i]
        }
        /* Append m to res */
        res = append(res, m)
        /* The value of m has been changed */
        fmt.Printf("lib: m:\n\n%s\n\n", m)
        /* When printing res, always mapping to the same memory block */
        fmt.Printf("lib: res:\n\n%s\n\n", res)
    }

    return res, err
}

结果如下,可以发现res的内容是一样的

m = map[comment:first_comment id:0]

res = [map[id:0 comment:first_comment]]

m = map[id:1 comment:first_comment]

res = [map[id:1 comment:first_comment] map[id:1 comment:first_comment]]

m = map[id:2 comment:first_comment]

res = [map[id:2 comment:first_comment] map[id:2 comment:first_comment] map[id:2 comment:first_comment]]

我的期望 res = [map[id:0 comment:first_comment] map[id:1 comment:first_comment] map[id:2 comment:first_comment]]

感谢收看

【问题讨论】:

  • 标记使用的 dbms,以获得更好的帮助 - 更快。
  • 切片就是这样工作的。也许你可以展示一个更短的独立程序?无论如何:您必须重新设计您的解决方案。
  • 在没有 sql 的较短程序中,可以追加切片。
  • 先检查Scan的错误。

标签: sql go


【解决方案1】:

根据Rows (https://golang.org/pkg/database/sql/#Rows.Scan)的文档:


Scan 将当前行中的列复制到 dest 指向的值中。

如果参数的类型为 *[]byte,Scan 会在该参数中保存相应数据的副本。副本归调用者所有,可以无限期修改和持有。可以通过使用 *RawBytes 类型的参数来避免复制;有关使用限制,请参阅 RawBytes 的文档。

如果参数的类型为 *interface{},Scan 会复制底层驱动程序提供的值而不进行转换。如果值是 []byte 类型,则复制一份,调用者拥有结果。


在您的情况下,您使用 RawBytes 作为 Scan 的参数。这可能是你遇到的问题。尝试其他类型作为 Scan 函数的参数。

【讨论】:

  • RawBytes 是一个字节片,它包含对数据库本身拥有的内存的引用。扫描到 RawBytes 后,切片仅在下一次调用 Next、Scan 或 Close 之前有效。
  • 谢谢,当我使用 []byte 而不是 Rawbytes 时,一切正常。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-28
  • 2015-03-20
  • 1970-01-01
相关资源
最近更新 更多