面试题·卷一

1、写出下面代码输出结果(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import (
"fmt"
)

func main() {
defer_call()
}

func defer_call() {
defer func() { fmt.Println("打印前") }()
defer func() { fmt.Println("打印中") }()
defer func() { fmt.Println("打印后") }()

panic("触发异常")
}

2、以下代码有什么问题,说明原因(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type student struct {
Name string
Age int
}

func pase_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
}
}

3、下面的代码会输出什么,并说明原因(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func main() {
runtime.GOMAXPROCS(1)
wg := sync.WaitGroup{}
wg.Add(20)
for i := 0; i < 10; i++ {
go func() {
fmt.Println("i: ", i)
wg.Done()
}()
}
for i := 0; i < 10; i++ {
go func(i int) {
fmt.Println("i: ", i)
wg.Done()
}(i)
}
wg.Wait()
}

4、下面代码会输出什么?(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
type People struct{}

func (p *People) ShowA() {
fmt.Println("showA")
p.ShowB()
}
func (p *People) ShowB() {
fmt.Println("showB")
}

type Teacher struct {
People
}

func (t *Teacher) ShowB() {
fmt.Println("teacher showB")
}

func main() {
t := Teacher{}
t.ShowA()
}

5、下面代码会触发异常吗?请详细说明(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
func main() {
runtime.GOMAXPROCS(1)
int_chan := make(chan int, 1)
string_chan := make(chan string, 1)
int_chan <- 1
string_chan <- "hello"
select {
case value := <-int_chan:
fmt.Println(value)
case value := <-string_chan:
panic(value)
}
}

6、下面代码会输出什么?(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}

func main() {
a := 1
b := 2
defer calc("1", a, calc("10", a, b))
a = 0
defer calc("2", a, calc("20", a, b))
b = 1
}

7、请写出以下输出内容(20分)

1
2
3
4
5
func main() {
s := make([]int, 5)
s = append(s, 1, 2, 3)
fmt.Println(s)
}

8、下面的代码有什么问题(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
type UserAges struct {
ages map[string]int
sync.Mutex
}

func (ua *UserAges) Add(name string, age int) {
ua.Lock()
defer ua.Unlock()
ua.ages[name] = age
}

func (ua *UserAges) Get(name string) int {
if age, ok := ua.ages[name]; ok {
return age
}
return -1
}

9、下面的迭代会有什么问题?(20分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func (set *threadSafeSet) Iter() <-chan interface{} {
ch := make(chan interface{})
go func() {
set.RLock()

for elem := range set.s {
ch <- elem
}

close(ch)
set.RUnlock()

}()
return ch
}

10、以下代码能编译过去吗?为什么?(20分)

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
package main

import (
"fmt"
)

type People interface {
Speak(string) string
}

type Student struct{}

func (stu *Student) Speak(think string) (talk string) {
if think == "bitch" {
talk = "You are a good boy"
} else {
talk = "hi"
}
return
}

func main() {
var peo People = Student{}
think := "bitch"
fmt.Println(peo.Speak(think))
}

参考答案

第1题

考点:defer执行顺序,panic的执行方式

结果:

1
2
3
4
打印后
打印中
“触发异常”
打印前

解析:“触发异常”可能出现在任何位置。defer是先进后出,逆序执行。
笔者猜测:panic()函数相当与go出去的一个协程,相关资料:https://blog.golang.org/defer-panic-and-recover, 将马上更新

第2题

解析:

1
2
3
在range循环中,变量是不会随着遍历过程发生变化的。
因此在代码中stu是不会变化的,变化的是放在&stu地址上的数据,
因此最后m中value都将是最后一个放在&stu中的值

第3题

解析:

1
2
3
4
5
6
先说说WaitGroup的用途:它能够一直等到所有的goroutine执行完成,并且阻塞主线程的执行,直到所有的goroutine执行完成。
这里要注意一下,他们的执行结果是没有顺序的,调度器不能保证多个 goroutine 执行次序,且进程退出时不会等待它们结束。
WaitGroup总共有三个方法:Add(delta int),Done(),Wait()。简单的说一下这三个方法的作用。
Add:添加或者减少等待goroutine的数量
Done:相当于Add(-1)
Wait:执行阻塞,直到所有的WaitGroup数量变成0

第4题

结果:

1
2
showA
showB

解析:

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
33
34
35
36
37
38
39
40
41
42
首先明确一点 go中没有继承关系。也不应该提及“继承”这个词,其中Trecher并没有继承Propler,而是嵌套People,
而t.ShowA()是一个语法糖,其实t.ShowA() = t.people.ShowA(),也就是说在嵌套结构中,go会优先调用本身方法,
如果本身没有此方法,就回去调用其所包含结构的方法。

本题中,showA()是Teacher不具有的,但是它所嵌套的People具有,因此回调用People.showA(),People.showA()
中调用了*People 的showB()当然会展示“shwoB”,而不是“teacher showB”

引申一点,
如果嵌套有两个结构,并且两个结构具有相同的方法,如何执行的?
例如:
type People struct{}

func (p *People) ShowA() {
fmt.Println("showA")
p.ShowB()
}
func (p *People) ShowB() {
fmt.Println("showB")
}

type Human struct{}

func (h *Human) ShowA() {
fmt.Println("Human showA")
}

type Teacher struct {
Human
People
}

func (t *Teacher) ShowB() {
fmt.Println("teacher showB")
}

func main() {
t := Teacher{}
t.ShowA()
}


答案是 编译报错,不支持这种情况的。

第6题

结果:

1
2
3
4
10 1 2 3
20 0 2 2
2 0 2 2
1 1 3 4

解析:

1
2
3
4
5
1、当程序运行到defer函数时,不会执行函数实现,但会将defer函数中的参数代码进行执行。
因此首先执行的是calc("10", a, b)),随后执行的是calc("2", a, calc("20", a, b))
得到第一行和第二行结果。
2、defer的执行结果是先进后出,从函数尾部向函数头部以此执行。因此会首先执行calc("2", a, calc("20", a, b)),
然后执行defer calc("1", a, calc("10", a, b)),相应打印第三行和第四行

第7题

结果:

1
0 0 0 0 0 1 2 3

解析:

1
make([]int,5)的含义是创建数组,并且数组初始化5个元素,5个元素的值为类型零值。

第10题

结果:

1
编译不过去

解析:

1
2
原因是Student并没有继承People,people中有Speak(string)string方法,而Student类型中没有Speak()方法,
代码中的Student方法是*Student类型的,所有 var peo People = Student{}是不符合规范的。