Golang 知识点复习/易错点记录
Laeni
2022-10-10~2023-02-14
通道
- 向关闭的通道发送请求会导致
panic
切片(Slice)
-
典型案例1
func main() { intSlice := []int{1, 2, 3, 4, 5} i1 := intSlice[:3] i2 := intSlice[2:] intSlice[2] = 0 fmt.Printf("intSlice: %v len: %v cap: %v\n", intSlice, len(intSlice), cap(intSlice)) fmt.Printf("i1: %v len: %v cap: %v\n", i1, len(i1), cap(i1)) fmt.Printf("i2: %v len: %v cap: %v\n", i2, len(i2), cap(i2)) } /* intSlice: [1 2 0 4 5] len: 5 cap: 5 i1: [1 2 0] len: 3 cap: 5 i2: [0 4 5] len: 3 cap: 3 */
上述示例说明:
- 切片底层是对数组的引用。
- 切片值传递时,底层数组虽然引用的是同一个,但是切片的长度和容量是复制的。
- 向后切片时,切片的容量会减小。(假如一直往后切片不知道会不会引起内存泄露)
gorutine
-
典型案例1
func main() { var wg sync.WaitGroup intSlice := []int{1, 2, 3, 4, 5} wg.Add(len(intSlice)) ans1, ans2, ans3 := 0, 0, 0 for _, v := range intSlice { vv := v go func(v3 int) { defer wg.Done() ans1 += v ans2 += vv ans3 += v3 }(v) } wg.Wait() fmt.Println(ans1, ans2, ans3) }
上述代码中
ans1
、ans2
和ans3
均不一定等于15
。ans2
和ans3
虽然使用的都是v
的复制,但是在多gorutine中操作同一个变量是导致它们值不一样的原因,而ans1
除了上述原因之外,还存在另一个原因:在for
循环中,v
只在第一次声明,后面都是修改第一次声明的变量的值,再加上闭包函数声明时引用的时变量的地址,而不是值复制,所以等实际gorutine执行时访问到的值可能已经发生了变化。但是实际验证时可能结果是固定的,原因gorutine太少,可能只会被一个线程执行,但是当增加gorutine数量时,可能就会被分配给多个线程,那样的话每次的结果可能就不一样了:
func main() { var wg sync.WaitGroup intSlice := make([]int, 10000) for i := range intSlice { intSlice[i] = i + 1 } wg.Add(len(intSlice)) ans1, ans2, ans3 := 0, 0, 0 for _, v := range intSlice { vv := v go func(v3 int) { defer wg.Done() ans1 += v ans2 += vv ans3 += v3 }(v) } wg.Wait() fmt.Println(ans1, ans2, ans3) }
其他
- 类型转换(
Type(expression)
)用于两种不同的类型,在type A B
中A
和B
是两种不同的类型,但是它们是兼容的,所以使用转换,而不是类型断言(expression.(Type)
);类型断言适用于“它本身就是那种类型“的情况,并不存在转换。