简介
网上找了几份golang面试代码看一下,总结一下
声明
正文
写出下面代码的输出结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33package main
import (
"fmt"
)
type student struct {
Name string
Age int
}
func main() {
m := pase_map()
for k, v := range m {
fmt.Printf("key = %s,value =%v\n", k, v)
}
}
func pase_map() map[string]*student {
m := make(map[string]*student)
stu := []student{{"joy", 12}, {"lei", 14}}
for _, v := range stu {
m[v.Name] = &v
}
return m
}执行结果
1
2key = joy,value =&{lei 14}
key = lei,value =&{lei 14}原因:for range使用副本
v
遍历mapm
,&v
指向同一个地址协程交替执行,使其能顺序输出1-20的自然数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23package main
import (
"fmt"
"time"
)
func main() {
for i:=1;i<=10;i++ {
go func(i int) {
fmt.Println(2*i-1)
}(i)
}
for i:=1;i<=10;i++ {
go func(i int) {
fmt.Println(2*i)
}(i)
}
time.Sleep(3*time.Second)
}方法一:
runtime.Gosched()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27package main
import (
"fmt"
"runtime"
"time"
)
func main() {
runtime.GOMAXPROCS(1)
go func() {
for i := 1; i <= 10; i++ {
fmt.Println(2*i - 1)
runtime.Gosched() //1
}
}()
go func() {
for i := 1; i <= 10; i++ {
fmt.Println(2 * i)
runtime.Gosched() //2
}
}()
time.Sleep(1 * time.Second)
}方法二:单核通道交互
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30package main
import (
"fmt"
"runtime"
"time"
)
func main() {
ch1 := make(chan int, 1)
ch2 := make(chan int, 0)
runtime.GOMAXPROCS(1)
for i := 1; i <= 10; i++ {
go func(i int) {
<-ch1
fmt.Println(2*i - 1)
ch2 <- 0
}(i)
}
for i := 1; i <= 10; i++ {
go func(i int) {
<-ch2
fmt.Println(2 * i)
ch1 <- 0
}(i)
}
ch1 <- 1
time.Sleep(1 * time.Second)
}总结:比较倾向于使用方法二,因为没有改变原有程序结构
写出代码运行结果,如有错误则指出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19package main
import "fmt"
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Print(err)
} else {
fmt.Print("no")
}
}()
defer func() {
panic("1111111111111")
}()
panic("22222222222")
}执行顺序为:
1
2
31. panic("22222222222") panic向上传递
2. panic("1111111111111") panic向上传递
3. recover() 接收panic,打印最后一个panic所以结果为:
1
1111111111111
select典型用法
如果有多个case都可以运行,select会随机公平地选出一个执行,其他不会执行。
如果没有可运行的case语句,且有default语句,那么就会执行default的动作。
如果没有可运行的case语句,且没有default语句,select将阻塞,直到某个case通信可以运行超时判断
比如在下面的场景中,使用全局resChan来接受response,如果时间超过3S,resChan中还没有数据返回,则第二条case将执行1
2
3
4
5
6
7
8
9
10
11
12
13
14
15var resChan = make(chan int)
// do request
func test() {
select {
case data := <-resChan:
doData(data)
case <-time.After(time.Second * 3):
fmt.Println("request time out")
}
}
func doData(data int) {
//...
}退出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23//主线程(协程)中如下:
var shouldQuit = make(chan struct{})
func main() {
{
//loop
}
//...out of the loop
select {
case <-shouldQuit:
cleanUp()
return
default:
}
//...
}
func cleanUp() {
//clean something
}
//再另外一个协程中,如果运行遇到非法操作或不可处理的错误,就向shouldQuit发送数据通知程序停止运行
close(shouldQuit)判断是否阻塞
在某些情况下是存在不希望channel缓存满了的需求的,可以用如下方法判断1
2
3
4
5
6
7
8
9
10func main() {
ch := make(chan int, 5)
//...
data := 0
select {
case ch <- data:
default:
//如果数据放不进去,就做相应操作,比如丢弃data。视需求而定
}
}