func Test_Closure_In_Func(t *testing.T) {
runtime.GOMAXPROCS(1)
wg := sync.WaitGroup{}
wg.Add(20)
for i := 0; i < 10; i++ {
go func() {
fmt.Println("A: ", i)
wg.Done()
}()
}
for i := 0; i < 10; i++ {
go func(i int) {
fmt.Println("B: ", i)
wg.Done()
}(i)
}
wg.Wait()
}
多个goroutine的执行是无序的,所以本题的输出将会是无序的。
但由于闭包的特性,在所有A相关的goroutine中,i是for循环的一个外部变量,i的地址不变,其值随遍历的进行而改变,最终i=10;所以,所有A相关的goroutine将会输出A:10;
在所有B相关的goroutine中,i是函数参数,在函数传入参数的过程中会发生值拷贝,所以i指向每一个具体遍历的值;所以,所有B相关的goroutine将会输出B:i
Golang面试题解析 3. 下面的代码会输出什么,并说明原因
package main
import (
"fmt"
)
type student struct {
Name string
Age int
}
func pase_student() map[string]*student {
m := make(map[string]*student)
stus := []student{
{Name: "zhou", Age: 24},
{Name: "li", Age: 23},
{Name: "wang", Age: 22},
}
for _, stu := range stus {
m[stu.Name] = &stu
}
return m
}
func main() {
students := pase_student()
for k, v := range students {
fmt.Printf("key=%s,value=%v \n", k, v)
}
}
理论依据: 遍历slice时,不可以使用&stu的方式获取slice中的子元素
&stu表示获取stu这个变量的地址,而该变量的地址表示指向stus[i]的地址,故而该变量的地址会随着遍历过程的进行而改变
该变量的地址在初始化时指向stus[0]的地址; 随着遍历过程的进行,该变量的地址会被修改为stus[i]的地址;最终该变量的地址会修改为stus[len - 1]的地址;
所以通过&stu获取的将会是stus中最后一个子元素的地址
整个遍历过程中,stu变量的变化可理解为如下过程:
var stu student
for _, stu = range stus {
m[stu.Name] = &stu
}
代码验证: get_slice_element_wrong_test.go Test_Get_Slice_Element_Wrong_Validation
理论依据: 正确的获取slice中子元素的方式应该是,先根据下标获取对应的子元素,再获取对应子元素的地址,根据地址定位实际的子元素并使用。
上述过程可以理解为如下代码:
for i, _ := range stus {
// 根据下标定位子元素
stu := stus[i]
// 根据地址获取子元素的实际信息
m[stu.Name] = &stu
}
代码验证: get_slice_element_wrong_test.go Test_Get_Slice_Element_Correct
Golang经典面试题上 2. 以下代码有什么问题,说明原因
func main() {
s := make([]int, 5)
s = append(s, 1, 2, 3)
fmt.Println(s)
}
golang 面试题 10、以下代码能编译过去吗?为什么?
// var: 用于声明变量的关键字
// chessMap: 数组名
// [11][11]int: 数组的容量(必须显式声明)及类型
var chessMap [11][11]int
golang slice/map/chan的初始化
【Golang】去除slice中重复的元素,认识空struct