- 先看下面代码,是否有问题。
1 2 3 4 5 6 7
| func main(){ const sh = "zhang" fmt.Println(&sh, sh)
var nl string = "san" fmt.Println(&nl, nl) }
|
运行结果:
1 2 3
| ☁ test_all go run main.go
./main.go:7:14: cannot take the address of sh
|
在go中,不同于变量是在运行时分配内存空间,常量通常会被编译器在预处理阶段直接展开,作为指令数据使用,所以常量无法寻址。
- 单向channel关闭
1 2 3 4 5 6 7 8 9
| func main(){ ch := make(chan string, 1000) ch <- "name" RecvSim(ch) } func RecvSim(ch <- chan string) { fmt.Println(<-ch) close(ch) }
|
1 2 3
| ☁ test_all go run main.go
./main.go:35:7: invalid operation: close(ch) (cannot close receive-only channel)
|
1 2 3 4 5 6 7 8 9
| func main(){ ch := make(chan string, 1000) SendSim(ch) }
func SendSim(ch chan <- string) { ch <- "zzz..." close(ch) }
|
- 判断下面代码输出的结果:
情况A:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| type T struct { ls []int }
func foo(t T) { t.ls[0] = 100 }
func main() { t := T{ ls: []int{1,2,3}, } foo(t)
fmt.Println(t.ls) }
|
正确答案是:[100,2,3]
情况B:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| type T struct { ls []int }
func foo(t T) { t.ls = append(t.ls, 100) t.ls[0] = 1000 }
func main() { t := T{ ls: []int{1,2,3}, } foo(t)
fmt.Println(t.ls) }
|
正确答案:[1,2,3]
函数foo参数t虽然是传传递,但是复制后的参数t的ls字段最开始指向底层的数组是公用的,所以情况A修改了第一个元素的值也会影响到原来的变量;而情况B犹豫追加了一个元素,导致函数foo的参数t底层数据进行了重新内存分配,指向了新的底层数组,所以不会影响原来的值。
- context.WithValue容易忽视的陷阱。
查看下面的代码,说出下面代码输出的结果:
1 2 3 4 5 6 7
| func main() { ctx0 := context.Background() ctx := context.WithValue(ctx0, "name", "zhangliang") ctx = context.WithValue(ctx0, "age", 12) fmt.Println(ctx.Value("name")) fmt.Println(ctx.Value("age")) }
|
正确结果是:
1 2 3
| ☁ test_all go run main.go <nil> 12
|
这是因为每组context只允许存储一对key-value,后面的age把前面的name覆盖了。正确写法是:
1 2 3 4 5 6 7
| func main() { ctx0 := context.Background() ctx1 := context.WithValue(ctx0, "name", "zhangliang") ctx2 := context.WithValue(ctx1, "age", 12) fmt.Println(ctx2.Value("name")) fmt.Println(ctx2.Value("age")) }
|
输出:
1 2 3
| ☁ test_all go run main.go zhangliang 12
|
此时的ctx2结构如下: