【Go】学习笔记

"Go has indeed become the language of cloud infrastructure" - Rob Pike interview

变量

var与:=

  • :=方式较为简洁,但只能在函数内使用该方式,var方式没有这个限制,var方式定义在汉书外的变量属于包内部的变量
  • 函数中以:=方式定义变量为主

内建变量类型

  • bool,string
  • (u)int, (u)int8, (u)int16, (u)int32, (u)int, uintptr
  • byte, rune
  • float32, float64, complex64, complex128
  • 变量类型写在变量名之后
  • 编译器可推测变量类型
  • 没有char, 只有rune
  • 原生支持复数类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
"fmt"
"math"
"math/cmplx"
)

func euler() {
// 欧拉公式 e^(i*Pi) + 1 = 0
fmt.Println(cmplx.Exp(1i * math.Pi) + 1)
fmt.Println(cmplx.Pow(math.E, 1i * math.Pi) + 1)
}

func main() {
euler()
}

// 打印内容
(0+1.2246467991473515e-16i)
(0+1.2246467991473515e-16i)

强制类型转换

go语言需要开发时强制类型转换,不会自动隐式转换

1
2
3
4
5
6
7
func triangle()  {
a, b := 3, 4
var c int
c = math.Sqrt(a*a + b*b) // 会在编译前idea便提示报错
c = int(math.Sqrt(float64(a * a + b * b))) // 正确写法
fmt.Println(c)
}

常量未声明类型,其类型是不确定的(数值可以作各种类型使用)

1
2
3
4
5
6
7
func consts()  {
// 强制类型转换
const a, b = 3, 4
var c int
c = int(math.Sqrt(a * a + b * b)) // a * a + b * b 部分可以不用加上强制类型转换
fmt.Println(c)
}

可以利用常量申明枚举类型

1
2
3
4
5
6
7
8
9
10
11
12
func enums()  {
const (
golang = iota
_
java
python
)
fmt.Println(golang, java, python)
}

// 输出
0 2 3

可以以iota为基础,生成一系列枚举数

1
2
3
4
5
6
7
8
9
10
11
12
13
func enums()  {
const (
b = 1 << (10 * iota)
kb
mb
gb
tb
)
fmt.Println(b, kb, mb, gb, tb)
}

// 输出
1 1024 1048576 1073741824 1099511627776

https://github.com/weitrue/note/blob/master/go/variable.go

指针

指针不能运算

1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import "fmt"

func main() {
var a int = 2
var pa *int = &a
*pa = 3
fmt.Println(a)
}

// 运行结果
3

参数传递—只有值传递一种方式

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
func swapV(a, b int) {
b, a = a, b
fmt.Println("in ", a, b, &a, &b)
}

func swapRN(a, b *int) {
// 局部变量交换值(地址)
b, a = a, b
fmt.Println("in ", a, b, *a, *b)
}

func swapR(a, b *int) {
// 交换变量值(地址)指向的值
*b, *a = *a, *b
fmt.Println("in ", a, b, *a, *b)
}

func pointerSwap() {
a, b := 3, 4
swapV(a, b)
fmt.Println("out", a, b, &a, &b)

a, b = 3, 4
swapRN(&a, &b)
fmt.Println("out", a, b, &a, &b)

a, b = 3, 4
swapR(&a, &b)
fmt.Println("out", a, b, &a, &b)

}

// 输出
in 4 3 0xc00001e0c8 0xc00001e0d0
out 3 4 0xc00001e0b8 0xc00001e0c0
in 0xc00001e0c0 0xc00001e0b8 4 3
out 3 4 0xc00001e0b8 0xc00001e0c0
in 0xc00001e0b8 0xc00001e0c0 4 3
out 4 3 0xc00001e0b8 0xc00001e0c0

https://github.com/weitrue/note/blob/master/go/pointer.go

容器

数组

Go 语言的数组有两种不同的创建方式

  • 一种是显式的指定数组大小
  • 一种是使用 [...]T 声明数组
    • Go 语言编译器会在的 cmd/compile/internal/gc.typecheckcomplit 函数中对该数组的大小进行推导
    • [...]T 这种初始化方式也只是 Go 语言为我们提供的一种语法糖,当我们不想计算数组中的元素个数时可以通过这种方法减少一些工作量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
func define()  {
var arr1 [5]int
arr2 := [3]int{1, 3, 5}
arr3 := [...]int{2, 4, 6, 8, 10}

var grid [4][5]bool
fmt.Println(arr1, arr2, arr3)
fmt.Println(grid)
}

// 输出
[0 0 0 0 0] [1 3 5] [2 4 6 8 10]
[[false false false false false] [false false false false false] [false false false false false] [false false false false false]]

[5]int和[10]int是不同类型

调用func f(arr [10]int)会拷贝数组

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
func printArr(arr [5]int)  {
arr[0] = 100
for i, v := range arr {
fmt.Println(i, v)
}
}

func arrTest() {
var arr1 [5]int
arr2 := [...]int{2, 4, 6, 8, 10}
fmt.Println()
printArr(arr2)
fmt.Println()
for i, v := range arr1 {
fmt.Println(i, v)
}
}

// 输出
0 100
1 0
2 0
3 0
4 0

0 100
1 4
2 6
3 8
4 10

0 0
1 0
2 0
3 0
4 0

若要改变数组的值 需要传入数组的地址,因此go语言一般不使用数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func printArrR(arr *[5]int)  {
arr[0] = 100
for i, v := range arr {
fmt.Println(i, v)
}
}

func arrTest() {
var arr1 [5]int
printArrR(&arr1)
fmt.Println()
fmt.Println(arr1)
}
// 输出
0 100
1 0
2 0
3 0
4 0

[100 0 0 0 0]

https://github.com/weitrue/note/blob/master/go/collections/array.go

切片

  • slice可以向后扩展,但不能向前扩展

  • s[i]不可超越len(s),向后扩展不可以超越底层数组cap(s)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func slice() {
arr := [...]int{1, 2, 3, 4, 5, 6, 7}
s1 := arr[2: 6]
fmt.Println(s1)
s2 := s1[3: 5]
fmt.Println(s2)
s3 := s1[3:6]
fmt.Println(s3)
}
//输出
[3 4 5 6]
[6 7]
panic: runtime error: slice bounds out of range [:6] with capacity 5

goroutine 1 [running]:
main.sliceDefine()
~/Projects/golang/src/offer/note/slices.go:20 +0x164
main.main()
~/Projects/golang/src/offer/note/ab_test_func.go:28 +0x20

  • 向slice添加元素,如果超越cap,系统会自动分配更大的底层数组

  • 由于值传递的原因,必须接收append的返回值s=append(s, val)

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
func sliceAppend() {
arr := [...]int{1, 2, 3, 4, 5, 6, 7, 8}
s1 := arr[2: 6]
fmt.Println(s1, cap(s1), len(s1))
s2 := s1[3: 5]
fmt.Println(s2)
s3 := append(s2, 10)
s4 := append(s3, 11)
s5 := append(s4, 12)
fmt.Println("s3, s4, s5=", s3, s4, s5)
fmt.Println(arr)

s6 := append(s1, 10)
s7 := append(s6, 11)
s8 := append(s7, 12)
fmt.Println("s6, s7, s8=", s6, s7, s8)
fmt.Println("cap(s6), cap(s7), cap(s8) =", cap(s6), cap(s7), cap(s8))
fmt.Println(arr)
}
// 输出
[3 4 5 6] 6 4
[6 7]
s3, s4, s5= [6 7 10] [6 7 10 11] [6 7 10 11 12]
cap(s3), cap(s4), cap(s5) = 3 6 6
[1 2 3 4 5 6 7 10]

s6, s7, s8= [3 4 5 6 10] [3 4 5 6 10 11] [3 4 5 6 10 11 12]
cap(s6), cap(s7), cap(s8) = 6 6 12
[1 2 3 4 5 6 10 11]

  • Zero value for slice is nil
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
func sliceDefine() {
var s []int
for i :=0; i <10; i++ {
fmt.Printf("%v, cap(s) = %d, len(s) = %d\n", s, cap(s), len(s))
s = append(s, 2*i + 1)
}

s1 := []int{2, 3, 4}
fmt.Printf("%v, cap(s1) = %d, len(s1) = %d\n", s1, cap(s1), len(s1))

s2 := make([]int, 8)
fmt.Printf("%v, cap(s2) = %d, len(s2) = %d\n", s2, cap(s2), len(s2))

s3 := make([]int, 8, 32)
fmt.Printf("%v, cap(s3) = %d, len(s3) = %d\n", s3, cap(s3), len(s3))

// 拷贝
copy(s2, s1)
fmt.Printf("%v, cap(s2) = %d, len(s2) = %d\n", s2, cap(s2), len(s2))

// 删除 没有内建函数,只能通过截取+append
s4 := append(s2[:2], s2[3:]...)
fmt.Printf("%v, cap(s4) = %d, len(s4) = %d\n", s4, cap(s4), len(s4))
}

//输出
[], cap(s) = 0, len(s) = 0
[1], cap(s) = 1, len(s) = 1
[1 3], cap(s) = 2, len(s) = 2
[1 3 5], cap(s) = 4, len(s) = 3
[1 3 5 7], cap(s) = 4, len(s) = 4
[1 3 5 7 9], cap(s) = 8, len(s) = 5
[1 3 5 7 9 11], cap(s) = 8, len(s) = 6
[1 3 5 7 9 11 13], cap(s) = 8, len(s) = 7
[1 3 5 7 9 11 13 15], cap(s) = 8, len(s) = 8
[1 3 5 7 9 11 13 15 17], cap(s) = 16, len(s) = 9
[2 3 4], cap(s1) = 3, len(s1) = 3
[0 0 0 0 0 0 0 0], cap(s2) = 8, len(s2) = 8
[0 0 0 0 0 0 0 0], cap(s3) = 32, len(s3) = 8
[2 3 4 0 0 0 0 0], cap(s2) = 8, len(s2) = 8
[2 3 0 0 0 0 0], cap(s4) = 8, len(s4) = 7

https://github.com/weitrue/note/blob/master/go/collections/slices.go

Map

  • 创建make(map[type]type)

  • key不存在时,获取value类型的初始值,需要if value, ok := m[key]; ok {...} 判断是否存在key

  • map使用哈希表,必须可以比较相等

  • 除了slice, map,function的内建类型都可以作为map的key,Struct类型不包含上述字段时,也可作为key

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func mapDefine()  {
m := map[int]string{
1: "aa",
2: "bb",
}
if v, ok := m[3]; ok {
fmt.Println(v)
} else {
panic("key not exists")
}
}

//输出
panic: key not exists

goroutine 1 [running]:
main.mapDefine()
/Users/wangpeng/Projects/golang/src/offer/note/maps.go:20 +0x1f6
main.main()
/Users/wangpeng/Projects/golang/src/offer/note/ab_test_func.go:32 +0x20

https://github.com/weitrue/note/blob/master/go/collections/maps.go

Rune

字符串在UTF-8编码中,一个中文占三个字节,

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
func strByte(s string)  {
if s == "" {
s = "yes,我喜欢你!"
}
for i, ch := range []byte(s) {
fmt.Printf("(%d, %X)", i, ch)
}
fmt.Println()
for i, ch := range s { // ch is a rune 其实是将s进行utf-8解码,解码后的字符会转成unicode,然后放入rune中
fmt.Printf("(%d, %X)", i, ch)
}
fmt.Println()
bytes := []byte(s)
for len(bytes) >0 {
ch, size := utf8.DecodeRune(bytes)
bytes = bytes[size:]
fmt.Printf("%c ", ch)
}
fmt.Println()
for i, ch := range []rune(s) {
fmt.Printf("(%d, %X)", i, ch)
}
}

// 输出
(0, 79)(1, 65)(2, 73)(3, 2C)(4, E6)(5, 88)(6, 91)(7, E5)(8, 96)(9, 9C)(10, E6)(11, AC)(12, A2)(13, E4)(14, BD)(15, A0)(16, EF)(17, BC)(18, 81)
(0, 79)(1, 65)(2, 73)(3, 2C)(4, 6211)(7, 559C)(10, 6B22)(13, 4F60)(16, FF01)
y e s , 我 喜 欢 你 !
(0, 79)(1, 65)(2, 73)(3, 2C)(4, 6211)(5, 559C)(6, 6B22)(7, 4F60)(8, FF01)

因此在需要使用rune

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
/**
* Version: 1.0.0
* Description: 获取字符串中不重复字串最大长度
**/
func maxNoRepeated(s string) int {
// 仅支持英文字符
// 字符下标映射
chNotRepeatIndex := make(map[byte] int)
// 最长串起始位置
start := 0
// 最长串长度
maxLength := 0
for i, ch := range []byte(s) {
if lastI, ok := chNotRepeatIndex[ch]; ok && lastI >= start {
start = lastI + 1
}
if i - start + 1 > maxLength {
maxLength = i - start + 1
}
chNotRepeatIndex[ch] = i
}
return maxLength
}

func maxNoRepeatedChn(s string) int {
// 通过rune
chNotRepeatIndex := make(map[rune] int)
start := 0
maxLength := 0
for i, ch := range []rune(s) {
if lastI, ok := chNotRepeatIndex[ch]; ok && lastI >= start {
start = lastI + 1
}
if i - start + 1 > maxLength {
maxLength = i - start + 1
}
chNotRepeatIndex[ch] = i
}
return maxLength
}

https://github.com/weitrue/note/blob/master/go/collections/strings.go

面向对象

支持封装,不支持继承和多态

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
import "fmt"

type Node struct {
Value int
Left, Right *Node
}

func (node Node) Print() {
fmt.Print(node.Value, " ")
}

func (node *Node) SetValue(value int) {
// 接收者使用指针才可以改变结构内容
if node == nil {
fmt.Println("Setting Value to nil node. Ignored.")
return
}
node.Value = value
}

func (node Node) SetValueNotUpdate(value int) {
// 值传递 node内容无法改变
if &node == nil {
fmt.Println("Setting Value to nil node. Ignored.")
return
}
node.Value = value
}

func CreateNode(value int) *Node {
// 返回局部变量地址,这样变量会在堆中声明,可以传到外部
return &Node{Value: value}
}

方法有接收者(值/指针接收者),需要改变内容必须使用指针接收者,结构体过大考虑用指针接收者

1
2
3
4
5
6
7
8
9
10
11
func main() {
node := Node{}
node.Print()
node.SetValueNotUpdate(10)
node.Print()
node.SetValue(10)
node.Print()
}

// 输出
0 0 10

nil也可以调用方法

1
2
3
4
5
6
7
func main() {
var pNode *Node
pNode.SetValue(30)
}

// 输出
Setting Value to nil node. Ignored.
1
2
3
4
5
6
7
8
9
10
11
12
13
func main() {
var pNode *Node
pNode.SetValueNotUpdate(20)
}

// 输出
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x109d0af]

goroutine 1 [running]:
main.main()
~/Projects/golang/src/offer/note/ab_test_func.go:50 +0x1f

https://github.com/weitrue/note/blob/master/go/object/tree.go

封装与包

首字母大写:public,首字母小写:private

为结构体定义的方法需要放在一个包下(可以是不同的文件)

扩充系统类型或者自定义类型方式:定义别名和使用组合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type Queue []int

func (q *Queue)Push(val int) error {
*q = append(*q, val)
return nil
}

func (q *Queue)Pop() (int,bool) {
if q.IsEmpty() {
return 0, false
}
head := (*q)[0]
*q = (*q)[1:]
return head, true
}

func (q *Queue)IsEmpty() bool {
return len(*q) == 0
}
1
2
3
4
5
6
7
8
type Node struct {
Value int
Left, Right *Node
}

type MyNode struct {
node *Node
}

https://github.com/weitrue/note/blob/master/go/object/queue.go

接口

鸭子类型

Duck Typing

接口由使用者定义

​ Python的在运行时才能知道被调用的对象是否实现某个方法

​ Java中编译前,调用的对象就必须实现接口所有方法

接口变量自带指针(参数传递也是值传递),因此几乎不需要使用接口指针

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
46
47
48
// offer/note/interfaces/mock/duck.go
package mock

type Duck struct {
Name string
}

func (d *Duck) GetName() string {
// 实现者没有指明实现了哪个接口
if d.Name != "" {
return d.Name
} else {
return "这是一个鸭子!"
}
}

// offer/note/interfaces/duckI.go
package interfaces

import "fmt"

type DuckI interface {
// 使用接口者 定义方法
GetName() string
}

func FindDuck(d DuckI) { // 接口变量自带指针
name := d.GetName()
fmt.Println(name)
}

// offer/note/main.go
package main

import (
"offer/note/interfaces"
"offer/note/interfaces/mock"
)

func main() {
interfaces.FindDuck(&mock.Duck{})
interfaces.FindDuck(&mock.Duck{Name:"这是一只假鸭子"})
}


// 输出
这是一个鸭子!
这是一只假鸭子
多态
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
type MemberRights interface {
Information () string
}

type BronzeMember struct {
Discount uint8
}

type SilverMember struct {
Discount uint8
}

type GoldMember struct {
Discount uint8
}

func (b *BronzeMember) Information () string {
return fmt.Sprintf("Discount:%d", b.Discount)
}

func (s *SilverMember) Information () string {
return fmt.Sprintf("Discount:%d", s.Discount)
}

func (g *GoldMember) Information () string {
return fmt.Sprintf("Discount:%d", g.Discount)
}

func Price (m MemberRights) {
fmt.Println(m.Information())
}

func main () {
b := &BronzeMember{Discount: 9}
Price(b)
s := &SilverMember{8}
Price(s)
g := new(GoldMember)
g.Discount = 7
Price(g)
}

任何类型

interface{}

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
type Queue []interface{}

func (q *Queue)Push(val interface{}) error {
*q = append(*q, val)
return nil
}

func (q *Queue)Pop() (interface{},bool) {
if q.IsEmpty() {
return 0, false
}
head := (*q)[0]
*q = (*q)[1:]
return head, true
}

func (q *Queue)IsEmpty() bool {
return len(*q) == 0
}

func main(){
q := interfaces.Queue{}
_ = q.Push("asd")
_ = q.Push(123)
if v, ok := q.Pop(); ok {
fmt.Println(v)
}
if v, ok := q.Pop(); ok {
fmt.Println(v)
}
}

// 输出
asd
123

组合

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// offer/note/interfaces/animals.go
package animal

import "fmt"

type AnimalsI interface {
DuckI
BehaviorI
}

func DuckBehavior(a AnimalsI) {
name := a.GetName()
dark := a.Shout("呱呱乱叫")
fmt.Println(name, dark)
fmt.Println(a.String())
}


// offer/note/interfaces/behaviorI.go
package animal

type BehaviorI interface {
Shout(dark string) string
}


// offer/note/interfaces/duckI.go
package animal

type DuckI interface {
GetName() string
}


// offer/note/interfaces/mock/duck.go
package mock

type Duck struct {
name string
bark string
}

func (d *Duck) GetName() string {
if d.name != "" {
return d.name
} else {
return "这是一个鸭子"
}
}

func (d *Duck) Shout(dark string) string {
if d.bark == ""{
return "呱呱呱呱的叫"
}else {
return dark
}
}

func (d *Duck) String() string {
return fmt.Sprintf("Duck: { name = %s, bark = %s }", d.name, d.bark)
}

// 输出
这是一个鸭子 呱呱呱呱的叫
Duck: { name = , bark = }

https://github.com/weitrue/note/tree/master/go/interfaces

常用接口

  • Stringer相当于toString()
1
2
3
type Stringer interface {
String() string
}
  • Reader
  • Writer
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
46
47
48
49
50
51
52
// io/io.go

// Reader is the interface that wraps the basic Read method.
//
// Read reads up to len(p) bytes into p. It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered. Even if Read
// returns n < len(p), it may use all of p as scratch space during the call.
// If some data is available but not len(p) bytes, Read conventionally
// returns what is available instead of waiting for more.
//
// When Read encounters an error or end-of-file condition after
// successfully reading n > 0 bytes, it returns the number of
// bytes read. It may return the (non-nil) error from the same call
// or return the error (and n == 0) from a subsequent call.
// An instance of this general case is that a Reader returning
// a non-zero number of bytes at the end of the input stream may
// return either err == EOF or err == nil. The next Read should
// return 0, EOF.
//
// Callers should always process the n > 0 bytes returned before
// considering the error err. Doing so correctly handles I/O errors
// that happen after reading some bytes and also both of the
// allowed EOF behaviors.
//
// Implementations of Read are discouraged from returning a
// zero byte count with a nil error, except when len(p) == 0.
// Callers should treat a return of 0 and nil as indicating that
// nothing happened; in particular it does not indicate EOF.
//
// Implementations must not retain p.
type Reader interface {
Read(p []byte) (n int, err error)
}

// Writer is the interface that wraps the basic Write method.
//
// Write writes len(p) bytes from p to the underlying data stream.
// It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// Write must return a non-nil error if it returns n < len(p).
// Write must not modify the slice data, even temporarily.
//
// Implementations must not retain p.
type Writer interface {
Write(p []byte) (n int, err error)
}

// ReadWriter is the interface that groups the basic Read and Write methods.
type ReadWriter interface {
Reader
Writer
}

函数

  • 函数可以有多个返回值,并且这些返回值可以起别名(别名多用于简单函数),别名与调用者的申明变量并无关联
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import "fmt"

func eval(a, b int, op string) (int, error) {
switch op {
case "+":
return a + b, nil
case "-":
return a - b, nil
case "*":
return a * b, nil
case "/":
r, _ := div(a, b)
return r, nil
default:
return 0, fmt.Errorf("unsupported operation")
}
}

func div(a, b int) (q, r int) {
return a/b, a%b
}
  • 一等公民 :变量、参数、返回值均可以是函数
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
package main

import (
"fmt"
"math"
"reflect"
"runtime"
)
func apply(op func(int, int) float64, a, b int) float64 {
//
p := reflect.ValueOf(op).Pointer()
opName := runtime.FuncForPC(p).Name()
fmt.Printf("Calling function %s with params (%d, %d)\n", opName, a, b)
return op(int(a), int(b))
}

func pow(a, b int) float64 {
return math.Pow(float64(a), float64(b))
}

func main() {
fmt.Println(apply(pow, 3, 4))

// 匿名函数方式
fmt.Println(apply(func(f, f2 int) float64 {
return math.Pow(float64(f), float64(f2))
}, 3, 4))
}

// 打印结果
Calling function main.pow with params (3, 4)
81
Calling function main.main.func1 with params (3, 4)
81
  • 可变参数列表,类似于Python中的*args
1
2
3
4
5
6
7
8
func sum(nums ...int) int {
// 函数可变参数列表
sum := 0
for i := range nums {
sum += nums[i]
}
return sum
}

https://github.com/weitrue/note/blob/master/go/functions/func.go

闭包

其中,func(i int)i为局部变量,sum为自由变量

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
46
47
48
49
50
51
52
53
54
55
56
func adder() func(int) int {
sum := 0
return func(i int) int {
sum += i
return sum
}
}

func TestAdder() {
a := adder()
for i := 0; i < 10 ; i++ {
fmt.Printf("0 + ... + %d = %d \n", i, a(i))
}
}

// 输出
0 + ... + 0 = 0
0 + ... + 1 = 1
0 + ... + 2 = 3
0 + ... + 3 = 6
0 + ... + 4 = 10
0 + ... + 5 = 15
0 + ... + 6 = 21
0 + ... + 7 = 28
0 + ... + 8 = 36
0 + ... + 9 = 45


// 正统函数式编程
type iAdder func(int) (int, iAdder)

func iAdd(base int) iAdder {
return func(v int) (int, iAdder) {
return base +v, iAdd(base+v)
}
}

func TestAdder() {
a2 := iAdd(0)
var s int
for i := 1; i <10; i++ {
s, a2 = a2(i)
fmt.Printf("0 + ... + %d = %d \n", i, s)
}
}

// 输出
0 + ... + 1 = 1
0 + ... + 2 = 3
0 + ... + 3 = 6
0 + ... + 4 = 10
0 + ... + 5 = 15
0 + ... + 6 = 21
0 + ... + 7 = 28
0 + ... + 8 = 36
0 + ... + 9 = 45

https://github.com/weitrue/note/blob/master/go/functions/closure.go

Python中的闭包

Python原生支持闭包

__closure__可以查看闭包内容

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
def adder():
s = 0

def f(v: int):
nonlocal s
s += v
return s

return f


if __name__ == "__main__":

a = adder()
for i in range(10):
print(i, a(i), a.__closure__)

# 输出
0 0 (<cell at 0x7f9048e7d3d0: int object at 0x106eb6290>,)
1 1 (<cell at 0x7f9048e7d3d0: int object at 0x106eb62b0>,)
2 3 (<cell at 0x7f9048e7d3d0: int object at 0x106eb62f0>,)
3 6 (<cell at 0x7f9048e7d3d0: int object at 0x106eb6350>,)
4 10 (<cell at 0x7f9048e7d3d0: int object at 0x106eb63d0>,)
5 15 (<cell at 0x7f9048e7d3d0: int object at 0x106eb6470>,)
6 21 (<cell at 0x7f9048e7d3d0: int object at 0x106eb6530>,)
7 28 (<cell at 0x7f9048e7d3d0: int object at 0x106eb6610>,)
8 36 (<cell at 0x7f9048e7d3d0: int object at 0x106eb6710>,)
9 45 (<cell at 0x7f9048e7d3d0: int object at 0x106eb6830>,)
Java中的闭包

1.8以后,可以使用Function接口和Lambda表达式可以创建函数对象;

1.8之前,可以使用Lambda表达式或者匿名内部类也可以实现闭包;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import javax.xml.ws.Holder;
import java.util.function.Function;

public class MyTest {

final Holder<Integer> sum = new Holder<>(0);

public Function<Integer, Integer>testClosure(){
// 闭包 使用Function接口和Lambda表达式可以创建函数对象
return (Integer value) -> {
sum.value += value;
return sum.value;
};
}

public static void main(String[] args) {
MyTest mt = new MyTest();
for (int i=0; i < 10; i++) {
System.out.println(i +", "+ mt.testClosure().apply(new Integer(i)));
}
}
}

闭包应用

为函数实现接口
实现函数遍历二叉树
单例模式,限制流量模式

文档

godoc -http :6060,生成网页文档

go doc 方法名(包括包名),查看方法注释

xxx_test.go生成示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func ExampleQueue_Pop() {
q := Queue{}
_ = q.Push("asd")
_ = q.Push(123)
if v, ok := q.Pop(); ok {
fmt.Println(v)
}
if v, ok := q.Pop(); ok {
fmt.Println(v)
}

//Output:
//asd
//123
}

测试

表格驱动测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func TestMaxNoRepeatedZhn(t *testing.T) {
tests := []struct{
s string
ans int
}{
{"a", 1},
{"yes, 我爱gogogo", 9},
{"abcadcb", 4},
{"黑化肥挥发发灰会花飞灰化肥挥发发黑会飞花", 8},
}

for _, tt := range tests {
act := MaxNoRepeatedZhn(tt.s)
if act != tt.ans {
t.Errorf("get %d for input %s , but expect %d", act, tt.s, tt.ans)
}
}
}

// 输出
=== RUN TestMaxNoRepeatedZhn
--- PASS: TestMaxNoRepeatedZhn (0.00s)
PASS

覆盖测试

go tool cover

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
Usage of 'go tool cover':
Given a coverage profile produced by 'go test':
go test -coverprofile=c.out

Open a web browser displaying annotated source code:
go tool cover -html=c.out # 常用

Write out an HTML file instead of launching a web browser:
go tool cover -html=c.out -o coverage.html

Display coverage percentages to stdout for each function:
go tool cover -func=c.out

Finally, to generate modified source code with coverage annotations
(what go test -cover does):
go tool cover -mode=set -var=CoverageVariableName program.go

Flags:
-V print version and exit
-func string
output coverage profile information for each function
-html string
generate HTML representation of coverage profile
-mode string
coverage mode: set, count, atomic
-o string
file for output; default: stdout
-var string
name of coverage variable to generate (default "GoCover")

Only one of -html, -func, or -mode may be set.

Benchmark

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func BenchmarkMaxNoRepeatedZhn(b *testing.B) {
s := "黑化肥挥发发灰会花飞灰化肥挥发发黑会飞花"
ans := 8

for i := 0; i < b.N; i++ {
act := MaxNoRepeatedZhn(s)
if act != ans {
b.Errorf("get %d for input %s , but expect %d", act, s, ans)
}
}
}


// 输出
goos: darwin
goarch: amd64
pkg: offer/note/collections
BenchmarkMaxNoRepeatedZhn
BenchmarkMaxNoRepeatedZhn-8 1097594 1024 ns/op
PASS

https://github.com/weitrue/note/collections/strings_test.go

pprof性能测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
xxx@xxxdeMacBook-Pro  ~/Projects/golang/src/offer/note/collections master ±✚ go test -bench . -cpuprofile cpu.out
goos: darwin
goarch: amd64
pkg: offer/note/collections
BenchmarkMaxNoRepeatedZhn-8 1286594 934 ns/op
PASS
ok offer/note/collections 2.656s
xxx@xxxdeMacBook-Pro  ~/Projects/golang/src/offer/note/collections master ±✚ go tool pprof cpu.out
Type: cpu
Time: Mar 2, 2021 at 6:03pm (CST)
Duration: 2.34s, Total samples = 2.05s (87.57%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) web
failed to execute dot. Is Graphviz installed? Error: exec: "dot": executable file not found in $PATH
(pprof)

failed to execute dot. Is Graphviz installed? Error: exec: "dot": executable file not found in $PATH是因为电脑未安装生成.svg文件的工具Graphviz

安装Graphviz
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
brew install graphviz
xxx@xxxdeMacBook-Pro  ~/Projects/golang/src/github.com  brew install graphviz
Error:
homebrew-core is a shallow clone.
homebrew-cask is a shallow clone.
To `brew update`, first run:
git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow
git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask fetch --unshallow
These commands may take a few minutes to run due to the large size of the repositories.
This restriction has been made on GitHub's request because updating shallow
clones is an extremely expensive operation due to the tree layout and traffic of
Homebrew/homebrew-core and Homebrew/homebrew-cask. We don't do this for you
automatically to avoid repeatedly performing an expensive unshallow operation in
CI systems (which should instead be fixed to not use shallow clones). Sorry for
the inconvenience!
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/libpng-1.6.37.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/freetype-2.10.4.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/fontconfig-2.13.1.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/jpeg-9d.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/libtiff-4.1.0_1.big_sur.bottle.tar.gz
######################################### 58.1%
curl: (56) LibreSSL SSL_read: SSL_ERROR_SYSCALL, errno 54
Error: Failed to download resource "libtiff"
Download failed: https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/libtiff-4.1.0_1.big_sur.bottle.tar.gz
Warning: Bottle installation failed: building from source.
==> Downloading https://download.osgeo.org/libtiff/tiff-4.1.0.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/webp-1.1.0.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/gd-2.3.0.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/libffi-3.3.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/pcre-8.44.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/glib-2.66.2_1.big_sur.bottle.tar.gz
########## 14.5%
curl: (56) LibreSSL SSL_read: SSL_ERROR_SYSCALL, errno 54
Error: Failed to download resource "glib"
Download failed: https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/glib-2.66.2_1.big_sur.bottle.tar.gz
Warning: Bottle installation failed: building from source.
==> Downloading https://raw.githubusercontent.com/Homebrew/formula-patches/6164294a75541c278f3863b111791376caa3ad26/glib/hardcoded-paths.diff
######################################################################## 100.0%
==> Downloading https://download.gnome.org/sources/glib/2.66/glib-2.66.2.tar.xz
==> Downloading from https://mirrors.ustc.edu.cn/gnome/sources/glib/2.66/glib-2.66.2.tar.xz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/jasper-2.0.22.big_sur.bottle.tar.gz
==> Downloading from https://d29vzk4ow07wi7.cloudfront.net/ad3715537b3001b9a8924896e5c4e7eb90b21bb37e7171d964de2008edb13910?response-content-disposition=attachment%3Bfilename%3D%22jasper-2.0.22.big_sur.bo
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/netpbm-10.86.17.big_sur.bottle.tar.gz
==> Downloading from https://d29vzk4ow07wi7.cloudfront.net/3540b31b88e9d8fc7288de5dac7b96be6f1c6652c604cfd167113bdf07738ca7?response-content-disposition=attachment%3Bfilename%3D%22netpbm-10.86.17.big_sur.
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/gts-0.7.6_2.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/lzo-2.10.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/pixman-0.40.0.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/cairo-1.16.0_3.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/gdk-pixbuf-2.42.0.big_sur.bottle.tar.gz
==> Downloading from https://d29vzk4ow07wi7.cloudfront.net/1819bb48f7487d522a69c564dca6fe5dff4da658269f067e47edccddfaab9440?response-content-disposition=attachment%3Bfilename%3D%22gdk-pixbuf-2.42.0.big_su
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/fribidi-1.0.10.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/pkg-config-0.29.2_3.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/gobject-introspection-1.66.1_1.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/graphite2-1.3.14.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/icu4c-67.1.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/harfbuzz-2.7.2.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/pango-1.48.0.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/librsvg-2.50.2.big_sur.bottle.tar.gz
##################### 29.6%
curl: (18) transfer closed with 28187304 bytes remaining to read
Error: Failed to download resource "librsvg"
Download failed: https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/librsvg-2.50.2.big_sur.bottle.tar.gz
Warning: Bottle installation failed: building from source.
==> Downloading https://download.gnome.org/sources/librsvg/2.50/librsvg-2.50.2.tar.xz
==> Downloading from https://mirrors.ustc.edu.cn/gnome/sources/librsvg/2.50/librsvg-2.50.2.tar.xz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/libtool-2.4.6_2.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/graphviz-2.44.1.big_sur.bottle.1.tar.gz
###################################### 52.9%
curl: (18) transfer closed with 6363689 bytes remaining to read
Error: Failed to download resource "graphviz"
Download failed: https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/graphviz-2.44.1.big_sur.bottle.1.tar.gz
Warning: Bottle installation failed: building from source.
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/autoconf-2.69.big_sur.bottle.4.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/automake-1.16.3.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/pkg-config-0.29.2_3.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/c393e3a39326eab27929f0f2ce40cb425e78bd8812166e6d835a08a8bf0c5f56--pkg-config-0.29.2_3.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/libpng-1.6.37.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/3bd2e2a75fbfc893d9acc20eeafc5274e260ed2ca39483ccbb1450a734bc6775--libpng-1.6.37.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/freetype-2.10.4.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/1399fc577f7998623378e7bb01f8a716a43eff701304059936d592a76d5a4d31--freetype-2.10.4.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/fontconfig-2.13.1.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/3790f4e94c8e7c868307933e3445a1244aadd794adaa6ed5f743533334489f93--fontconfig-2.13.1.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/jpeg-9d.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/7ed5b41c2937740eca747a8077502454971fbbe02cfb5cfbd9b9e7379345d0cd--jpeg-9d.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/libtiff-4.1.0_1.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/webp-1.1.0.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/1ae441623b4c63d896b5566300b24c06d772ff9f2676d7c9bd692ff6b8e22edb--webp-1.1.0.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/gd-2.3.0.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/d71eed744db212a24cc7f607842253aacf0e1d25cd7891c884ec7ffc969162ac--gd-2.3.0.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/libffi-3.3.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/49892306006d42a1f69ae4b36ff44b37c8e7170f6cf73a20e97f10bf9fa10e72--libffi-3.3.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/pcre-8.44.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/9998b74590fa558f4c346e9770a62495d4aca8e992d0e883435e3574303ee241--pcre-8.44.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/glib-2.66.2_1.big_sur.bottle.tar.gz
######################################################################## 100.0%
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/jasper-2.0.22.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/86ba13e63264cbcafb0dbec9e35960e2662f9e4bde0306bd52984bf487e6581a--jasper-2.0.22.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/netpbm-10.86.17.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/9f8fa63491038e9bb811b03f09660342641c7f8132169bdb3800631d8d2b189e--netpbm-10.86.17.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/gts-0.7.6_2.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/eab94b3870ce0c63232e9a992963c8a32ea53a7efa8a09e639066b40ae0a132b--gts-0.7.6_2.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/lzo-2.10.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/0020e09d8a2c473efa8db2af4b402358f5184578c801c7a7650de6c8bedca06a--lzo-2.10.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/pixman-0.40.0.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/ddf94c89d763f2c63c00ce2090ff16d5abd832ca0e1e9beb2245da3cc159ce41--pixman-0.40.0.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/cairo-1.16.0_3.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/8ad096f68fcc70615ff77f14b50eafbed94e4a261c7860dcda41ba25c7d12f52--cairo-1.16.0_3.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/gdk-pixbuf-2.42.0.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/fb191d15b537de812241fe664f4149209c4d58ce3fbdd5e98a292fe495420f39--gdk-pixbuf-2.42.0.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/fribidi-1.0.10.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/9013c8a0aeb1d2fee9a999ef14adfb2416fef4e8399d87a65d753d44a586427b--fribidi-1.0.10.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/gobject-introspection-1.66.1_1.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/a7f9a1bcb83a7d322e495d163f15b4b8f4d0c05649eeacfcef2681a23b3eb8dd--gobject-introspection-1.66.1_1.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/graphite2-1.3.14.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/5ce053636ab73845d956142cfd518a21701d3ec972e73367d204b81619b8b845--graphite2-1.3.14.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/icu4c-67.1.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/ddca8d436054c0f9c8c333d2e8dd957ccd3902680baf619e4baed434c9806998--icu4c-67.1.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/harfbuzz-2.7.2.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/1aead0f1ab97b4307a9c487a3191213ff63fd200d5eb9be947a11e8ca78df24a--harfbuzz-2.7.2.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/pango-1.48.0.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/eded163bf136aa7a73e07f22c8b16f3a406bbd849b865246a95ee89ecd60aa4e--pango-1.48.0.big_sur.bottle.tar.gz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/librsvg-2.50.2.big_sur.bottle.tar.gz
################################################### 71.3%
curl: (18) transfer closed with 11492026 bytes remaining to read
Error: Failed to download resource "librsvg"
Download failed: https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/librsvg-2.50.2.big_sur.bottle.tar.gz
Warning: Bottle installation failed: building from source.
==> Downloading https://download.gnome.org/sources/librsvg/2.50/librsvg-2.50.2.tar.xz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/0388827e738392e3705cbb8800e43f279723caf5126ba50c7cd4e1ca5e2af872--librsvg-2.50.2.tar.xz
==> Downloading https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/bottles/libtool-2.4.6_2.big_sur.bottle.tar.gz
Already downloaded: /Users/wangpeng/Library/Caches/Homebrew/downloads/59a8e4e9bff6153b4cb25fda4de99648330e04fefdd7e9c98f92fa4d049a9f30--libtool-2.4.6_2.big_sur.bottle.tar.gz
==> Downloading https://www2.graphviz.org/Packages/stable/portable_source/graphviz-2.44.1.tar.gz
#################### 28.5%
######################################################################## 100.0%
==> Installing dependencies for graphviz: autoconf, automake, pkg-config, libpng, freetype, fontconfig, jpeg, libtiff, webp, gd, libffi, pcre, glib, jasper, netpbm, gts, lzo, pixman, cairo, gdk-pixbuf, fribidi, gobject-introspection, graphite2, icu4c, harfbuzz, pango, librsvg and libtool
==> Installing graphviz dependency: autoconf
==> Pouring autoconf-2.69.big_sur.bottle.4.tar.gz
🍺 /usr/local/Cellar/autoconf/2.69: 68 files, 3.0MB
==> Installing graphviz dependency: automake
==> Pouring automake-1.16.3.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/automake/1.16.3: 131 files, 3.4MB
==> Installing graphviz dependency: pkg-config
==> Pouring pkg-config-0.29.2_3.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/pkg-config/0.29.2_3: 11 files, 656.6KB
==> Installing graphviz dependency: libpng
==> Pouring libpng-1.6.37.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/libpng/1.6.37: 27 files, 1.3MB
==> Installing graphviz dependency: freetype
==> Pouring freetype-2.10.4.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/freetype/2.10.4: 64 files, 2.3MB
==> Installing graphviz dependency: fontconfig
==> Pouring fontconfig-2.13.1.big_sur.bottle.tar.gz
==> Regenerating font cache, this may take a while
==> /usr/local/Cellar/fontconfig/2.13.1/bin/fc-cache -frv
🍺 /usr/local/Cellar/fontconfig/2.13.1: 531 files, 3.6MB
==> Installing graphviz dependency: jpeg
==> Pouring jpeg-9d.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/jpeg/9d: 21 files, 953.8KB
==> Installing graphviz dependency: libtiff
==> Pouring libtiff-4.1.0_1.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/libtiff/4.1.0_1: 247 files, 4.2MB
==> Installing graphviz dependency: webp
==> Pouring webp-1.1.0.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/webp/1.1.0: 39 files, 2.4MB
==> Installing graphviz dependency: gd
==> Pouring gd-2.3.0.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/gd/2.3.0: 34 files, 1.4MB
==> Installing graphviz dependency: libffi
==> Pouring libffi-3.3.big_sur.bottle.tar.gz
==> Caveats
libffi is keg-only, which means it was not symlinked into /usr/local,
because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.

For compilers to find libffi you may need to set:
export LDFLAGS="-L/usr/local/opt/libffi/lib"
export CPPFLAGS="-I/usr/local/opt/libffi/include"

For pkg-config to find libffi you may need to set:
export PKG_CONFIG_PATH="/usr/local/opt/libffi/lib/pkgconfig"

==> Summary
🍺 /usr/local/Cellar/libffi/3.3: 17 files, 540.2KB
==> Installing graphviz dependency: pcre
==> Pouring pcre-8.44.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/pcre/8.44: 204 files, 5.8MB
==> Installing graphviz dependency: glib
==> Pouring glib-2.66.2_1.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/glib/2.66.2_1: 436 files, 15.5MB
==> Installing graphviz dependency: jasper
==> Pouring jasper-2.0.22.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/jasper/2.0.22: 42 files, 1.5MB
==> Installing graphviz dependency: netpbm
==> Pouring netpbm-10.86.17.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/netpbm/10.86.17: 410 files, 17.7MB
==> Installing graphviz dependency: gts
==> Pouring gts-0.7.6_2.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/gts/0.7.6_2: 27 files, 1.4MB
==> Installing graphviz dependency: lzo
==> Pouring lzo-2.10.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/lzo/2.10: 31 files, 570.7KB
==> Installing graphviz dependency: pixman
==> Pouring pixman-0.40.0.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/pixman/0.40.0: 14 files, 1.3MB
==> Installing graphviz dependency: cairo
==> Pouring cairo-1.16.0_3.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/cairo/1.16.0_3: 119 files, 5.9MB
==> Installing graphviz dependency: gdk-pixbuf
==> Pouring gdk-pixbuf-2.42.0.big_sur.bottle.tar.gz
==> /usr/local/Cellar/gdk-pixbuf/2.42.0/bin/gdk-pixbuf-query-loaders --update-cache
🍺 /usr/local/Cellar/gdk-pixbuf/2.42.0: 149 files, 3.8MB
==> Installing graphviz dependency: fribidi
==> Pouring fribidi-1.0.10.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/fribidi/1.0.10: 67 files, 669.0KB
==> Installing graphviz dependency: gobject-introspection
==> Pouring gobject-introspection-1.66.1_1.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/gobject-introspection/1.66.1_1: 191 files, 12.7MB
==> Installing graphviz dependency: graphite2
==> Pouring graphite2-1.3.14.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/graphite2/1.3.14: 18 files, 291.7KB
==> Installing graphviz dependency: icu4c
==> Pouring icu4c-67.1.big_sur.bottle.tar.gz
==> Caveats
icu4c is keg-only, which means it was not symlinked into /usr/local,
because macOS provides libicucore.dylib (but nothing else).

If you need to have icu4c first in your PATH run:
echo 'export PATH="/usr/local/opt/icu4c/bin:$PATH"' >> ~/.zshrc
echo 'export PATH="/usr/local/opt/icu4c/sbin:$PATH"' >> ~/.zshrc

For compilers to find icu4c you may need to set:
export LDFLAGS="-L/usr/local/opt/icu4c/lib"
export CPPFLAGS="-I/usr/local/opt/icu4c/include"

For pkg-config to find icu4c you may need to set:
export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig"

==> Summary
🍺 /usr/local/Cellar/icu4c/67.1: 258 files, 71.8MB
==> Installing graphviz dependency: harfbuzz
==> Pouring harfbuzz-2.7.2.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/harfbuzz/2.7.2: 68 files, 6.4MB
==> Installing graphviz dependency: pango
==> Pouring pango-1.48.0.big_sur.bottle.tar.gz
🍺 /usr/local/Cellar/pango/1.48.0: 64 files, 3MB
==> Installing graphviz dependency: librsvg
==> Pouring librsvg-2.50.2.big_sur.bottle.tar.gz
tar: Error opening archive: Failed to open '/Users/wangpeng/Library/Caches/Homebrew/downloads/3eb605900a29b02eb026199f14474efc43e313ee2b9de389706c795eebdc24f5--librsvg-2.50.2.big_sur.bottle.tar.gz'
Error: Failure while executing; `tar xof /Users/wangpeng/Library/Caches/Homebrew/downloads/3eb605900a29b02eb026199f14474efc43e313ee2b9de389706c795eebdc24f5--librsvg-2.50.2.big_sur.bottle.tar.gz -C /var/folders/zs/2875szcx7jn6lbmqd0jfbprr0000gn/T/d20210302-22554-102pbtw` exited with 1. Here's the output:
tar: Error opening archive: Failed to open '/Users/wangpeng/Library/Caches/Homebrew/downloads/3eb605900a29b02eb026199f14474efc43e313ee2b9de389706c795eebdc24f5--librsvg-2.50.2.big_sur.bottle.tar.gz'

Warning: Bottle installation failed: building from source.
==> Installing dependencies for librsvg: libssh2 and rust
==> Installing librsvg dependency: libssh2
==> Pouring libssh2-1.9.0_1.big_sur.bottle.tar.gz
tar: Error opening archive: Failed to open '/Users/wangpeng/Library/Caches/Homebrew/downloads/45db0c196aa97bf6c0a9c6e7787ad2cd0d14d563c03d0f4e0d52392a0f3a1c81--libssh2-1.9.0_1.big_sur.bottle.tar.gz'
Error: Failure while executing; `tar xof /Users/wangpeng/Library/Caches/Homebrew/downloads/45db0c196aa97bf6c0a9c6e7787ad2cd0d14d563c03d0f4e0d52392a0f3a1c81--libssh2-1.9.0_1.big_sur.bottle.tar.gz -C /var/folders/zs/2875szcx7jn6lbmqd0jfbprr0000gn/T/d20210302-22554-qzrgbb` exited with 1. Here's the output:
tar: Error opening archive: Failed to open '/Users/wangpeng/Library/Caches/Homebrew/downloads/45db0c196aa97bf6c0a9c6e7787ad2cd0d14d563c03d0f4e0d52392a0f3a1c81--libssh2-1.9.0_1.big_sur.bottle.tar.gz'

Warning: Bottle installation failed: building from source.
==> Downloading https://libssh2.org/download/libssh2-1.9.0.tar.gz
######################################################################## 100.0%
==> ./configure --prefix=/usr/local/Cellar/libssh2/1.9.0_1 --disable-examples-build --with-openssl --with-libz --with-libssl-prefix=/usr/local/opt/openssl@1.1
==> make install
🍺 /usr/local/Cellar/libssh2/1.9.0_1: 184 files, 969.9KB, built in 33 seconds
==> Installing librsvg dependency: rust
==> Pouring rust-1.47.0.big_sur.bottle.tar.gz
tar: Error opening archive: Failed to open '/Users/wangpeng/Library/Caches/Homebrew/downloads/f1482d118ddb120ff152e8f8aa88afa9bebc5674cc42aebca96249cffbdd8bdb--rust-1.47.0.big_sur.bottle.tar.gz'
Error: Failure while executing; `tar xof /Users/wangpeng/Library/Caches/Homebrew/downloads/f1482d118ddb120ff152e8f8aa88afa9bebc5674cc42aebca96249cffbdd8bdb--rust-1.47.0.big_sur.bottle.tar.gz -C /var/folders/zs/2875szcx7jn6lbmqd0jfbprr0000gn/T/d20210302-22554-16tqegl` exited with 1. Here's the output:
tar: Error opening archive: Failed to open '/Users/wangpeng/Library/Caches/Homebrew/downloads/f1482d118ddb120ff152e8f8aa88afa9bebc5674cc42aebca96249cffbdd8bdb--rust-1.47.0.big_sur.bottle.tar.gz'

Warning: Bottle installation failed: building from source.
==> Downloading https://static.rust-lang.org/dist/rustc-1.47.0-src.tar.gz
######################################################################## 100.0%
==> ./configure --prefix=/usr/local/Cellar/rust/1.47.0 --release-channel=stable
==> make
Last 15 lines from /Users/wangpeng/Library/Logs/Homebrew/rust/02.make:
error: failed to get `cc` as a dependency of package `bootstrap v0.0.0 (/private/tmp/rust-20210302-29879-dftrmf/rustc-1.47.0-src/src/bootstrap)`

Caused by:
failed to fetch `https://github.com/rust-lang/crates.io-index`

Caused by:
network failure seems to have happened
if a proxy or similar is necessary `net.git-fetch-with-cli` may help here
https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli

Caused by:
http parser error: stream ended at an unexpected time; class=Http (34)
failed to run: /private/tmp/rust-20210302-29879-dftrmf/rustc-1.47.0-src/build/x86_64-apple-darwin/stage0/bin/cargo build --manifest-path /private/tmp/rust-20210302-29879-dftrmf/rustc-1.47.0-src/src/bootstrap/Cargo.toml
Build completed unsuccessfully in 0:33:17
make: *** [all] Error 1

READ THIS: https://docs.brew.sh/Troubleshooting

These open issues may also help:
rust 1.50.0 https://github.com/Homebrew/homebrew-core/pull/70922
Rust-dependent formulae on Apple Silicon - upstream issue tracker https://github.com/Homebrew/homebrew-core/issues/68301

defer/recover在简单web服务应用

代码结构

https://github.com/weitrue/note/tree/master/go/web/

包管理

gopm 获取无法下载的包

go get -v github.com/gpmgo/gopm

github地址:https://github.com/gpmgo/gopm

文档路径:https://github.com/gpmgo/docs/tree/master/zh-CN

安装踩坑:

1
2
3
4
github.com/codegangsta/cli: github.com/codegangsta/cli@v1.22.5: parsing go.mod:
module declares its path as: github.com/urfave/cli
but was required as: github.com/codegangsta/cli

关闭go mod即可成功安装

工具

OSV-扫描仪

github

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- Scan a docker image 扫描基于Debian的docker镜像包:
osv-scanner -D docker_image_name

- Scan a package lockfile 扫描特定锁定文件:
osv-scanner -L path/to/lockfile

- Scan an SBOM file 只检查SBOM中依赖项中的漏洞:
osv-scanner -S path/to/sbom_file

- Scan multiple directories recursively 扫描目录:
osv-scanner -r directory1 directory2 ...

- Skip scanning git repositories:
osv-scanner --skip-git -r|-D target

- Output result in JSON format:
osv-scanner --json -D|-L|-S|-r target
爬虫相关
Middleware

bytebufferpool

  • 依托sync.Pool进行了二次封装。
  • defaultSize设置每次创建buffer的默认大小,超过maxSize的buffer不会被放回去。
  • 分组统计不同大小buffer的使用次数,例如0-64bytes的buffer被使用的次数。
  • 引入校准机制,动态计算defaultSize和maxSize。
其他

Q&A

go http client protocol error: received DATA after END_STREAM

received DATA after END_STREAM只会存在于http2协议中,因此需要设置http client中的ForceAttempHTTP2=false。

解决

context canceled

增加客户端请求超时时间。

解决

面试题

基础语法

Q1 =:= 的区别?

Q2 指针的作用?

Q3 Go 允许多个返回值吗?

Q4 Go 有异常类型吗?

Q5 什么是协程(Goroutine)

Q6 如何高效地拼接字符串

Q7 什么是 rune 类型

Q8 如何判断 map 中是否包含某个 key ?

Q9 Go 支持默认参数或可选参数吗?

Q10 defer 的执行顺序

Q11 如何交换 2 个变量的值?

Q12 Go 语言 tag 的用处?

Q13 如何判断 2 个字符串切片(slice) 是相等的?

Q14 字符串打印时,%v%+v 的区别

Q15 Go 语言中如何表示枚举值(enums)

Q16 空 struct{} 的用途

实现原理

Q1 init() 函数是什么时候执行的?

Q2 Go 语言的局部变量分配在栈上还是堆上?

Q3 2 个 interface 可以比较吗?

Q4 两个 nil 可能不相等吗?

Q5 简述 Go 语言GC(垃圾回收)的工作原理

Q6 函数返回局部变量的指针是否安全?

Q7 非接口非接口的任意类型 T() 都能够调用 *T 的方法吗?反过来呢?

并发编程

Q1 无缓冲的 channel 和 有缓冲的 channel 的区别?

Q2 什么是协程泄露(Goroutine Leak)?

Q3 Go 可以限制运行时操作系统线程的数量吗?

代码输出

常量与变量

下列代码的输出是:

1
2
3
4
5
6
7
8
9
func main() {
const (
a, b = "golang", 100
d, e
f bool = true
g
)
fmt.Println(d, e, g)
}

下列代码的输出是:

1
2
3
4
5
6
7
8
func main() {
const N = 100
var x int = N

const M int32 = 100
var y int = M
fmt.Println(x, y)
}

下列代码的输出是:

1
2
3
4
5
func main() {
var a int8 = -1
var b int8 = -128 / a
fmt.Println(b)
}

下列代码的输出是:

1
2
3
4
5
func main() {
const a int8 = -1
var b int8 = -128 / a
fmt.Println(b)
}

下面的程序的运行结果是?

1
2
3
4
5
6
func main() {
i := 1
j := 2
i, j = j, i
fmt.Printf("%d%d\n", i, j)
}

下面的程序的运行结果是?

1
2
3
4
5
6
7
8
package main

import "fmt"

func main() {
var i float64 = 3 / 2
fmt.Print(i)
}

下面的程序的运行结果是?

1
2
3
4
5
6
7
8
9
func incr(p *int) int {
*p++
return *p
}
func main() {
v := 1
incr(&v)
fmt.Println(v)
}

下面的程序的运行结果是?

1
2
3
4
5
6
7
8
9
func incr(v int) int {
v++
return v
}
func main() {
v := 1
incr(v)
fmt.Println(v)
}
作用域

下列代码的输出是:

1
2
3
4
5
6
7
8
9
10
func main() {
var err error
if err == nil {
err := fmt.Errorf("err")
fmt.Println(1, err)
}
if err != nil {
fmt.Println(2, err)
}
}

下面的程序的运行结果是?

1
2
3
4
5
6
7
8
func main() {
x := 1
{
x := 2
fmt.Print(x)
}
fmt.Println(x)
}
defer 延迟调用

下列代码的输出是:

1
2
3
4
5
6
7
8
9
10
11
12
type T struct{}

func (t T) f(n int) T {
fmt.Print(n)
return t
}

func main() {
var t T
defer t.f(1).f(2)
fmt.Print(3)
}

下列代码的输出是:

1
2
3
4
5
6
7
8
func f(n int) {
defer fmt.Println(n)
n += 100
}

func main() {
f(1)
}

下列代码的输出是:

1
2
3
4
5
6
7
func main() {
n := 1
defer func() {
fmt.Println(n)
}()
n += 100
}

下列代码的输出是:

1
2
3
4
5
6
7
8
func main() {
n := 1
if n == 1 {
defer fmt.Println(n)
n += 100
}
fmt.Println(n)
}

下面的程序的运行结果是?

1
2
3
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}
数组与切片

下面的程序的运行结果是?

1
2
3
4
5
6
func main() {
x := []string{"a", "b", "c"}
for v := range x {
fmt.Print(v)
}
}

下面的程序的运行结果是?

1
2
3
4
5
6
func main() {
x := []string{"a", "b", "c"}
for _, v := range x {
fmt.Print(v)
}
}

下面的程序的运行结果是?

1
2
3
4
5
6
7
8
9
10
func main() {
strs := []string{"one", "two", "three"}
for _, s := range strs {
go func() {
time.Sleep(1 * time.Second)
fmt.Printf("%s ", s)
}()
}
time.Sleep(3 * time.Second)
}

下面的程序的运行结果是?

1
2
3
4
5
6
7
8
9
10
func main() {
strs := []string{"one", "two", "three"}
for _, s := range strs {
go func(ss string) {
time.Sleep(1 * time.Second)
fmt.Printf("%s ", ss)
}(s)
}
time.Sleep(3 * time.Second)
}

下面的程序的运行结果是?

1
2
3
4
5
6
7
8
9
10
package main

import (
"fmt"
)

func main() {
v := [...]int{1: 2, 3: 4}
fmt.Println(len(v))
}

下面的程序的运行结果是?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
type Slice []int
func NewSlice() Slice {
return make(Slice, 0)
}
func (s* Slice) Add(elem int) *Slice {
*s = append(*s, elem)
fmt.Print(elem)
return s
}
func main() {
s := NewSlice()
defer s.Add(1).Add(2)
s.Add(3)
}

选择题

1.下面属于关键字的是()

A. func

B. def

C. struct

D. class​

2.定义一个包内全局字符串变量,下面语法正确的是 ()

A. var str string

B. str := “”

C. str = “”

D. var str = “”

3.通过指针变量 p 访问其成员变量 name,下面语法正确的是()

A. p.name

B. (*p).name

C. (&p).name

D. p->name

4.关于接口和类的说法,下面说法正确的是()

A. 一个类只需要实现了接口要求的所有函数,我们就说这个类实现了该接口

B. 实现类的时候,只需要关心自己应该提供哪些方法,不用再纠结接口需要拆得多细才合理

C. 类实现接口时,需要导入接口所在的包

D. 接口由使用方按自身需求来定义,使用方无需关心是否有其他模块定义过类似的接口

5.关于字符串连接,下面语法正确的是()

A. str := ‘abc’ + ‘123’

B. str := “abc” + “123”

C. str := ‘123’ + “abc”

D. fmt.Sprintf(“abc%d”, 123)

6.关于协程,下面说法正确是()

A. 协程和线程都可以实现程序的并发执行

B. 线程比协程更轻量级

C. 协程不存在死锁问题

D. 通过channel来进行协程间的通信

7.关于init函数,下面说法正确的是()

A. 一个包中,可以包含多个init函数

B. 程序编译时,先执行导入包的init函数,再执行本包内的init函数

C. main包中,不能有init函数

D. init函数可以被其他函数调用

8.关于循环语句,下面说法正确的有()

A. 循环语句既支持for关键字,也支持while和do-while

B. 关键字for的基本使用方法与C/C++中没有任何差异

C. for循环支持continue和break来控制循环,但是它提供了一个更高级的break,可以选择中断哪一个循环

D. for循环不支持以逗号为间隔的多个赋值语句,必须使用平行赋值的方式来初始化多个变量

9.对于函数定义:

1
2
3
4
5
6
7
func add(args ...int) int {
sum := 0
for _, arg := range args {
sum += arg
}
return sum
}

下面对add函数调用正确的是()

A. add(1, 2)

B. add(1, 3, 7)

C. add([]int{1, 2})

D. add([]int{1, 3, 7}...)

10.关于类型转化,下面语法正确的是()

1
2
3
type MyInt int
var i int = 1
var j MyInt = i
1
2
3
type MyInt int
var i int = 1
var j MyInt = (MyInt)i
1
2
3
type MyInt int
var i int = 1
var j MyInt = MyInt(i)
1
2
3
type MyInt int
var i int = 1
var j MyInt = i.(MyInt) // Invalid type assertion: i.(MyInt) (non-interface type int on left)

11.关于局部变量的初始化,下面正确的使用方式是()

A. var i int = 10

B. var i = 10

C. i := 10

D. i = 10

12.关于const常量定义,下面正确的使用方式是()

1
2
const Pi float64 = 3.14159265358979323846
const zero = 0.0
1
2
3
4
const (
size int64 = 1024
eof = -1
)
1
2
3
4
const (
ERR_ELEM_EXIST error = errors.New("element already exists")
ERR_ELEM_NT_EXIST error = errors.New("element not exists")
) // Const initializer 'errors.New("element already exists")' is not a constant
1
2
const u, v float32 = 0, 3
const a, b, c = 3, 4, "foo"

13.关于布尔变量b的赋值,下面错误的用法是()

A. b = true

B. b = 1 // Cannot use '1' (type untyped int) as type bool in assignment

C. b = bool(1) //Cannot convert expression of type int to type bool

D. b = (1 == 2)

14.下面的程序的运行结果是()

1
2
3
4
5
6
7
8
func main() {
if (true) {
defer fmt.Printf("1")
} else {
defer fmt.Printf("2")
}
fmt.Printf("3")
}

A. 321

B. 32

C. 31

D. 13

15.关于switch语句,下面说法正确的有()

A. 条件表达式必须为常量或者整数

B. 单个case中,可以出现多个结果选项

C. 需要用break来明确退出一个case

D. 只有在case中明确添加fallthrough关键字,才会继续执行紧跟的下一个case

16.golang中没有隐藏的this指针,这句话的含义是()

A. 方法施加的对象显式传递,没有被隐藏起来

B. golang沿袭了传统面向对象编程中的诸多概念,比如继承、虚函数和构造函数

C. golang的面向对象表达更直观,对于面向过程只是换了一种语法形式来表达

D. 方法施加的对象不需要非得是指针,也不用非得叫this

17.golang中的引用类型包括()

A. 数组切片

B. map

C. channel

D. interface

18.golang中的指针运算包括()

A. 可以对指针进行自增或自减运算

B. 可以通过“&”取指针的地址

C. 可以通过“*”取指针指向的数据

D. 可以对指针进行下标运算

19.关于main函数(可执行程序的执行起点),下面说法正确的是()

A. main函数不能带参数

B. main函数不能定义返回值

C. main函数所在的包必须为main包

D. main函数中可以使用flag包来获取和解析命令行参数

20.下面赋值正确的是()

A. var x = nil

B. var x interface{} = nil

C. var x string = nil

D. var x error = nil

21.关于整型切片的初始化,下面正确的是()

A. s := make([]int)

B. s := make([]int, 0)

C. s := make([]int, 5, 10)

D. s := []int{1, 2, 3, 4, 5}

22.从切片中删除一个元素,下面的算法实现正确的是()

1
2
3
4
5
6
7
8
9
10
11
12
13
func (s *Slice)Remove(value interface{}) error {
for i, v := range *s {
if isEqual(value, v) {
if i== len(*s) - 1 {
*s = (*s)[:i]
}else {
*s = append((*s)[:i],(*s)[i + 2:]...)
}
return nil
}
}
return ERR_ELEM_NT_EXIST
}
1
2
3
4
5
6
7
8
9
func (s *Slice)Remove(value interface{}) error {
for i, v := range *s {
if isEqual(value, v) {
*s = append((*s)[:i],(*s)[i + 1:])
return nil
}
}
return ERR_ELEM_NT_EXIST
}
1
2
3
4
5
6
7
8
9
func (s *Slice)Remove(value interface{}) error {
for i, v := range *s {
if isEqual(value, v) {
delete(*s, v)
return nil
}
}
return ERR_ELEM_NT_EXIST
}
1
2
3
4
5
6
7
8
9
func (s *Slice)Remove(value interface{}) error {
for i, v := range *s {
if isEqual(value, v) {
*s = append((*s)[:i],(*s)[i + 1:]...)
return nil
}
}
return ERR_ELEM_NT_EXIST
}

23.关于变量的自增和自减操作,下面语句正确的是()

1
2
i := 1
i++
1
2
i := 1
j = i++ // ',', ';', new line or '}' expected, got '++'
1
2
i := 1
++i
1
2
i := 1
i--

24.关于函数声明,下面语法错误的是()

A. func f(a, b int) (value int, err error)

B. func f(a int, b int) (value int, err error)

C. func f(a, b int) (value int, error)

D. func f(a int, b int) (int, int, error)

25.如果Add函数的调用代码为:

1
2
3
4
5
6
7
func main() {
var a Integer = 1
var b Integer = 2
var i interface{} = &a
sum := i.(*Integer).Add(b)
fmt.Println(sum)
}

则Add函数定义正确的是()

1
2
3
4
type Integer int
func (a Integer) Add(b Integer) Integer {
return a + b
}
1
2
3
4
type Integer int
func (a Integer) Add(b *Integer) Integer {
return a + *b
}
1
2
3
4
type Integer int
func (a *Integer) Add(b Integer) Integer {
return *a + b
}
1
2
3
4
type Integer int
func (a *Integer) Add(b *Integer) Integer {
return *a + *b
}

26.如果Add函数的调用代码为:

1
2
3
4
5
6
7
func main() {
var a Integer = 1
var b Integer = 2
var i interface{} = a
sum := i.(Integer).Add(b)
fmt.Println(sum)
}

则Add函数定义正确的是()

1
2
3
4
type Integer int
func (a Integer) Add(b Integer) Integer {
return a + b
}
1
2
3
4
type Integer int
func (a Integer) Add(b *Integer) Integer {
return a + *b
}
1
2
3
4
type Integer int
func (a *Integer) Add(b Integer) Integer {
return *a + b
}
1
2
3
4
type Integer int
func (a *Integer) Add(b *Integer) Integer {
return *a + *b
}

27.关于GetPodAction定义,下面赋值正确的是()

1
2
3
4
5
6
7
8
9
type Fragment interface {
Exec(transInfo *TransInfo) error
}
type GetPodAction struct {
}
func (g GetPodAction) Exec(transInfo *TransInfo) error {
...
return nil
}

A. var fragment Fragment = new(GetPodAction)

B. var fragment Fragment = GetPodAction

C. var fragment Fragment = &GetPodAction{}

D. var fragment Fragment = GetPodAction{}

28.关于GoMock,下面说法正确的是()

A. GoMock可以对interface打桩

B. GoMock可以对类的成员函数打桩

C. GoMock可以对函数打桩

D. GoMock打桩后的依赖注入可以通过GoStub完成

29.关于接口,下面说法正确的是()

A. 只要两个接口拥有相同的方法列表(次序不同不要紧),那么它们就是等价的,可以相互赋值

B. 如果接口A的方法列表是接口B的方法列表的子集,那么接口B可以赋值给接口A

C. 接口查询是否成功,要在运行期才能够确定

D. 接口赋值是否可行,要在运行期才能够确定

30.关于channel,下面语法正确的是()

A. var ch chan int

B. ch := make(chan int)

C. <- ch

D. ch <-

31.关于同步锁,下面说法正确的是()

A. 当一个goroutine获得了Mutex后,其他goroutine就只能乖乖的等待,除非该goroutine释放这个Mutex

B. RWMutex在读锁占用的情况下,会阻止写,但不阻止读

C. RWMutex在写锁占用情况下,会阻止任何其他goroutine(无论读和写)进来,整个锁相当于由该goroutine独占

D. Lock()操作需要保证有Unlock()或RUnlock()调用与之对应

32.golang中大多数数据类型都可以转化为有效的JSON文本,下面几种类型除外()

A. 指针

B. channel

C. complex

D. 函数

33.关于go vendor,下面说法正确的是()

A. 基本思路是将引用的外部包的源代码放在当前工程的vendor目录下面

B. 编译go代码会优先从vendor目录先寻找依赖包

C. 可以指定引用某个特定版本的外部包

D. 有了vendor目录后,打包当前的工程代码到其他机器的$GOPATH/src下都可以通过编译

34.flag是bool型变量,下面if表达式符合编码规范的是()

A. if flag == 1

B. if flag

C. if flag == false

D. if !flag

35.value是整型变量,下面if表达式符合编码规范的是()

A. if value == 0

B. if value

C. if value != 0

D. if !value

流程图


【Go】学习笔记
https://weitrue.github.io/2021/02/07/golang/
作者
Pony W
发布于
2021年2月7日
许可协议