【问题标题】:Cannot reuse a single variable in for loop无法在 for 循环中重用单个变量
【发布时间】:2017-06-23 12:13:19
【问题描述】:

我想创建一个指针并在每次迭代中使用它,但在 and 我得到所有相同的值。所以我找到了在每次迭代中创建指针的解决方案。 但是这种方法似乎浪费了很多内存。

有没有办法在 Go 中重用相同的变量?

这是我的代码

func GetSchedules(start, end time.Time, usr *user.User) ([]*Scheduler, error) {
    queryStr := []string{"SELECT account_id,link,text,time,image_links from", Table, "where user_id=?"}
    var results = make([]*Scheduler, 0)
    rows, err := DB.MYSQL_DB.Query(strings.Join(queryStr, " "), usr.Id.Hex())
    if nil != err {
        return results, err
    }
    defer rows.Close()
    a := new(Scheduler)
    for rows.Next() {
        
        cols := []interface{}{&a.AccountId, &a.Link, &a.Text, &a.Time, &a.Images}
        fmt.Println(rows.Scan(cols...))
        results = append(results, a)

    }

    return results, nil
}

这里的问题在于名为 a 的变量,尽管我在每次迭代中都将新内容扫描到其中,但它只是一直显示最后一个,并且结果切片多次只包含最后一项

【问题讨论】:

  • 上面的代码应该给你不同的值,因为你在每次迭代中分配a。那么是哪一个问题呢?
  • 是的,但我不想每次都分配,因为如果我每次都分配意味着我需要每次都释放,而这不能在 go 中完成,所以 gc 会干扰更多@putu
  • 我只是将代码更新为不起作用的代码,这样就不会再混淆了
  • 您不能创建 1 个值,并且以某种方式拥有多个不同的值。创建你需要的值,不用担心 GC。如果 GC 由于某种原因成为问题,请举例说明该特定问题。
  • @JimB 关键是我创建了一个变量,但我在数组中更新它,就在那儿我要附加我想附加的值而不是对实际变量的引用,同时写这个评论我才明白该怎么做谢谢:)

标签: pointers go closures


【解决方案1】:

在您证明它是应用程序的瓶颈之前,不要担心 GC。从 DB 读取数据时,GC 永远不会成为您的瓶颈。这是一个简单的基准测试:

func BenchmarkReallocate(b *testing.B) {
    for i := 0; i < b.N; i++ {
        results := make([]*foo, 0)
        for i := 0; i < 100; i++ {
            f := new(foo)
            f.bar = "baz"
            results = append(results, f)
        }
    }
}

func BenchmarkReuse(b *testing.B) {
    for i := 0; i < b.N; i++ {
        results := make([]*foo, 0)
        var f *foo
        for i := 0; i < 100; i++ {
            f = new(foo)
            f.bar = "baz"
            results = append(results, f)
        }
    }
}

运行go test -bench . -benchmem的结果:

BenchmarkReallocate-8         300000          4416 ns/op        3640 B/op        108 allocs/op
BenchmarkReuse-8              300000          4359 ns/op        3640 B/op        108 allocs/op
PASS

所以最终两种方式都会导致完全相同的分配数量。

从 DB 到 struct 的典型读取如下所示:

rows, err := db.Query("SELECT * FROM foo")
if nil != err {
    return nil, err
}
defer rows.Close()
results := make([]*Scheduler, 0)
for rows.Next() {
    var s Scheduler
    if err := rows.Scan(&s.Id, &s.Name, &s.Something); err != nil {
        return nil, err
    }
    results = append(results, &s)
}
if err := rows.Err(); err != nil { // Don't forget to check rows.Err()
    return nil, err
}
return results, nil

【讨论】:

    猜你喜欢
    • 2017-05-02
    • 2020-04-05
    • 1970-01-01
    • 1970-01-01
    • 2013-10-12
    • 1970-01-01
    • 2015-05-22
    • 1970-01-01
    相关资源
    最近更新 更多