Golang变量的作用域注意事项

244 阅读1分钟

Golang可以通过:=声明的同时为变量赋值,还有变量的作用域也需要注意。for循环体中声明的变量作用域从for循环开始到花括号结束。 给出一组学生的各科成绩,可能有重复的,学生的姓名唯一,按照姓名对分数求和。

package main

import "fmt"

type student struct {
	Score int
	Name string
}

func printMap(m map[string]*student) {
	for k, v := range m {
		fmt.Println(k, v)
	}
}

func main() {
	s := make([]student, 0)
	s = append(s, student{1, "s1"})
	s = append(s, student{1, "s2"})
	s = append(s, student{2, "s1"})
	s = append(s, student{1, "s3"})

	m := make(map[string]*student)
	for idx, v := range s {
		_, ok := m[v.Name]
		if !ok {
			m[v.Name] = &v
		} else {
			m[v.Name].Score += v.Score
		}
		fmt.Println(idx)
		printMap(m)
	}

	printMap(m)
}

上面代码最终的输出:

s1 &{1 s3}
s2 &{1 s3}
s3 &{1 s3}

因为v的作用域在整个for循环,每次赋值的是v的地址,固定不变,所有value都被赋值为同一个值了。改成如下代码:

package main

import "fmt"

type student struct {
	Score int
	Name string
}

func printMap(m map[string]*student) {
	for k, v := range m {
		fmt.Println(k, v)
	}
}

func main() {
	s := make([]student, 0)
	s = append(s, student{1, "s1"})
	s = append(s, student{1, "s2"})
	s = append(s, student{2, "s1"})
	s = append(s, student{1, "s3"})

	m := make(map[string]*student)
	for idx, v := range s {
		_, ok := m[v.Name]
		if !ok {
			m[v.Name] = &s[idx]
		} else {
			m[v.Name].Score += v.Score
		}
	}

	printMap(m)
}

输出:

s1 &{3 s1}
s2 &{1 s2}
s3 &{1 s3}