在for循环中不能重复使用同一个变量。

huangapple go评论82阅读模式
英文:

Cannot reuse a single variable in for loop

问题

我想在每次迭代中创建一个指针并在其中使用它,但最后得到的所有值都相同。所以我找到了一种解决方案,即在每次迭代中创建指针。

但是这种方法似乎浪费了很多内存。

在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()
    for rows.Next() {
        a := new(Scheduler)
        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的变量上,尽管我在每次迭代中将新的内容扫描到它中,但它只显示最后一个,并且结果切片只包含多个相同的最后一个项。

英文:

I want to create a pointer and use it in every iteration but in the and I get all the same values. So I found the solution using creating the pointer in every iteration.
But this approach seems wasting a lot of memory.

Is there a way to reuse the same variable in Go?

Here is my code

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
}

hereThe problem is with the variable called a although I am scanning new stuff into it in every iteration it just keeps showing the last one and the results slice contains just the last item multiple times

答案1

得分: 4

在你的应用程序中,除非有证据表明垃圾回收(GC)是一个瓶颈,否则不必担心它。当从数据库读取数据时,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

所以最终两种方式产生的分配数量完全相同。

从数据库读取到结构体的典型代码如下:

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 { // 不要忘记检查 rows.Err()
    return nil, err
}
return results, nil
英文:

Don't worry about GC until you have proof that it is a bottleneck in your application. When reading data from DB, GC will never be a bottleneck for you. This is a simple benchmark:

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

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

Results of running 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

So in the end both ways result in exactly the same amount of allocations.

And the typical reading from DB into struct looks like this:

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

huangapple
  • 本文由 发表于 2017年6月23日 20:13:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/44721188.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定