Golang 面试题总结 I

Golang 中goroutine之间用什么来通信的

用的channel

buffered channel vs unbuffered channel

  1. buffered channel 有容量, 发送者在channel容量未填满前不会阻塞直到容量满了,接受者在channel未空前不会阻塞直到channel变空。

  2. unbuffered channel 发送者做发送操作之后,同时必须有一个接受者做接受操作。常用来做goroutine之间的同步。

make vs new

make: 只用来分配map, slice, channel, 返回一个类型的初始化零值。make初始化这些类型的内部数据结构,为使用做好准备。
new: 分配内存,但不初始化。返回类型T的零值指针。

slice 内部结构

slice 内部有一个指针指向底层的数组,还有长度和容量,分别表示当前slice的元素个数以及从指针开始处到数组末尾的长度。

1
2
ss := []int{1,2,3,4,5,6,7}
s1 := ss[1:5] // len(s1)=4, cap(s1) = 6

从一个slice中切分出来的slice添加元素对原来的slice是否有影响

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
43
44
45
package main

import (
"fmt"
)

func main() {
ss := []int{1,2,3,4,5,6,7}
s1 := ss[1:5]

fmt.Println(len(s1), cap(s1))
fmt.Println(ss, s1)

s1 = append(s1, 10)
fmt.Println(len(s1), cap(s1))
fmt.Println(ss, s1)

s1 = append(s1, 11)
fmt.Println(len(s1), cap(s1))
fmt.Println(ss, s1)

s1 = append(s1, 12)
fmt.Println(len(s1), cap(s1))
fmt.Println(ss, s1)

fmt.Println("Hello, playground")
}
/*
4 6
7 7
[1 2 3 4 5 6 7] [2 3 4 5]
5 6
[1 2 3 4 5 10 7] [2 3 4 5 10]
6 6
7 7
[1 2 3 4 5 10 11] [2 3 4 5 10 11]
7 12
[1 2 3 4 5 10 11] [2 3 4 5 10 11 12]
8 12
7 7
[1 2 3 4 5 10 11] [2 3 4 5 10 11 12 1000]
Hello, playground
*/

有影响,会改动原始slice里面元素的值,*但是不会改变原来slice的长度和容量*

说说对goroutine的理解

  • goroutine 是并发运行的function或method

  • goroutine 是轻量级的线程,创建一个goroutine开销较小。

  • goroutine 被多路复用到多个os线程上。当一个goroutine出现阻塞的时候,一个新的os thread将被创建去运行其他的运行的goroutine。

  • goroutine 使用channel来通信。

function 和 method 定义上的区别

区别就是定义方式不一样

1
2
3
4
5
// method
func (v *Type) Method() {}

// func
func Func() {}

defer 的执行顺序

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

import (
"fmt"
)

func main() {
defer fmt.Println("defer 1")
defer fmt.Println("defer 2")
defer fmt.Println("defer 3")

fmt.Println("main")
}
/*
main
defer 3
defer 2
defer 1
*/
与定义的相反顺序执行

panic recorver

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
"fmt"
)

func main() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("%T, %v\n", e, e)
}
}()

panicFunc()
}

func panicFunc() {
panic("call panic ")
}
/*
string, call panic
*/

golang init 函数的调用

golang 中init是在执行main开始前调用的
多个init是按照定义的顺序执行的

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

import (
"fmt"
)

var v = setV()

func init() {
fmt.Println("init 1")
}

func init() {
fmt.Println("init 2")
}

func main() {
fmt.Println(v)
}

func setV() int {
fmt.Println("setV")
return 42
}
/*
setV
init 1
init 2
42
*/

##