Go笔记

抽空学习Go语言。

Go笔记

参考书籍:

朱荣鑫,黄迪璇,张天. Go语言高并发与微服务实战[M]. 北京:中国铁道出版社有限公司,2020.

代码同步更新在GitHub:HearyShen/LearnGo

1 基本变量

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

import (
"fmt"
"math"
"unicode/utf8"
)

// run with command:
// go run src\1_variables.go

func main() {
// 3 ways to declare and initialize a variable
fmt.Printf("3 ways to declare and init a variable:\n")

var a int = 100
var b = "100"
c := 0.17

fmt.Printf("a value = %v (%T)\n", a, a)
fmt.Printf("b value = %v (%T)\n", b, b)
fmt.Printf("c value = %v (%T)\n", c, c)
fmt.Println()

// swap variables
fmt.Printf("Easy way to swap variables:\n")
v1 := 1
v2 := 2
fmt.Printf("before swap: v1 = %v (%T), v2 = %v (%T)\n", v1, v1, v2, v2)

v1, v2 = v2, v1
fmt.Printf("after swap: v1 = %v (%T), v2 = %v (%T)\n", v1, v1, v2, v2)
fmt.Println()

/*
Integer
signed: int8, int16, int32, int64
unsigned: uint8, uint16, uint32, uint64
*/
var vUint16 uint16 = math.MaxUint8 + 1
// vUint16 = math.MaxUint16 + 1 // src\1_variables.go:37:9: constant 256 overflows uint16
fmt.Printf("vUint16 = %v (%T)\n", vUint16, vUint16)

var vUint8 uint8 = uint8(vUint16)
fmt.Printf("vUint8 = %v (%T)\n", vUint8, vUint8) // truncated: 0000 0001 (0000 0000)

/*
Float
float32, float64
*/
var vFloat32 float32 = math.E
var vFloat64 float64 = math.E
fmt.Printf("vFloat32 = %f (%T)\n", vFloat32, vFloat32)
fmt.Printf("vFloat64 = %.10f (%T)\n", vFloat64, vFloat64)

/*
Bool
true/false, can not cast to integer types
*/
var vBool bool = true
fmt.Printf("vBool = %v (%T)\n", vBool, vBool)

/*
String
*/
var vStr string = "你好, Go!"
fmt.Printf("vStr = \"%s\" (%T)\n", vStr, vStr)
fmt.Printf("byte len of vStr = %v\n", len(vStr)) // 3*2 + 5*1 = 11, chinese character uses 3 bytes
fmt.Printf("rune len of vStr = %v\n", utf8.RuneCountInString(vStr)) // 7
// traverse each unicode character
for i, h := range vStr {
fmt.Printf("[%v:%c]", i, h)
}
fmt.Println()

/*
Pointer
*/
var ptrStr *string = &vStr
fmt.Printf("ptrStr = %v (%T)\n", ptrStr, ptrStr)
fmt.Printf("*ptrStr = %v (%T)\n", *ptrStr, *ptrStr)

/*
Struct
*/
var vStruct struct {
id int
name string
salary float32
}
vStruct.id = 1
vStruct.name = "Mike"
vStruct.salary = 123.45
fmt.Printf("vStruct = %v (%T)\n", vStruct, vStruct)
}


2 命令行参数flag

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 (
"flag"
"fmt"
)

// run with command:
// go run src\2_flag.go --username mike --password 123456 --id 1

func main() {
// argument name, default value, tips
var username *string = flag.String("username", "guest", "a string of username")

var password string
flag.StringVar(&password, "password", "123", "a string of password")

id := flag.Int("id", 0, "an integer of id")

flag.Parse()
fmt.Printf("username = %v, password = %v, id = %v\n", *username, password, *id)
}

3 常量const

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

import "fmt"

// run with command:
// go run src\3_const.go

func main() {
const helloStr = "Hello, world!"
const (
name = "Mike"
salary = 123.45
)
fmt.Printf("%v (%T)", name, name)

name = "Tom" // cannot assign to name
fmt.Printf("%v (%T)", name, name)

ptrName := &name // cannot take the address of name
*ptrName = "Tom"
fmt.Printf("%v (%T)", name, name)
}


4 类型type

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"

// run with command:
// go run src\4_type.go

type aliasInt = int // declare an alias for int
type myInt int // defines a new type

// Person is type of a struct
type BasicPerson struct {
name string
age uint8
}

func main() {
var vAliasInt aliasInt
fmt.Printf("vAliasInt = %v (%T)\n", vAliasInt, vAliasInt)

var vMyInt myInt
fmt.Printf("vMyint = %v (%T)\n", vMyInt, vMyInt)

var person BasicPerson
person.name = "Mike"
person.age = 20
fmt.Printf("person = %v (%T)\n", person, person)
}


5 if-else条件

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

import (
"flag"
"fmt"
)

// run with command:
// go run src\5_ifelse.go --score 100

func main() {
score := flag.Int("score", -1, "Score of a test")

flag.Parse()
fmt.Printf("score = %v (%T)\n", *score, *score)

if *score < 60 {
fmt.Println("Fail to pass")
} else if *score < 80 {
fmt.Println("Fine")
} else if *score <= 100 {
fmt.Println("Excellent")
} else {
fmt.Println("Wrong score")
}
}


6 switch-case条件

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

import (
"flag"
"fmt"
)

// run with command:
// go run src\6_switchcase.go -score 100 -course CPP

func main() {
score := flag.Int("score", -1, "Score of a test")
course := flag.String("course", "CPP", "Course name")
flag.Parse()

fmt.Printf("score = %v (%T)\n", *score, *score)
fmt.Printf("course = %v (%T)\n", *course, *course)

switch {
case *score < 60:
fmt.Println("fail to pass")
break
case *score < 80:
fmt.Println("fine")
break
case *score <= 100:
fmt.Println("excellent")
break
default:
fmt.Println("wrong score")
}

switch *course {
case "CPP":
fmt.Println("C plus plus")
break
case "PY":
fmt.Println("Python")
break
default:
fmt.Println("Unknown")
}
}

7 for-loop循环

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

import "fmt"

// run with commands:
// go run src\7_forloop.go

// Golang only has for loop
// Golang does not support while and do-while loop

func main() {
for i := 0; i < 10; i++ {
fmt.Println(i)
}
}

8 数组array

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

import "fmt"

func main() {
// init array
var colors [3]string
colors[0] = "Red"
colors[1] = "Green"
colors[2] = "Blue"
fmt.Println(colors)

// init array with initial values
languages := [...]string{"C", "C++", "Java"}
fmt.Println(languages)

// init array with new(type), returns a pointer
nations := new([3]string)
nations[0] = "China"
nations[1] = "India"
nations[2] = "Japan"
fmt.Println(*nations)
}

9 切片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
package main

import "fmt"

// run with commands:
// go run src\9_slice.go

// slice is a variable length sequence of data

func main() {
// [...]int{} marks a fixed length array,
// while []int{} declares a variable length slice
slice := []int{1, 2, 3, 4, 5, 6}
printSlice("slice", slice)
printSlice("subSlice", slice[3:])

// slice can be appended with one or more elements
// If it has sufficient capacity, the destination is resliced to accommodate the new elements.
// If it does not, a new underlying array will be allocated.
slice = append(slice, 7, 8)
printSlice("slice", slice)
printSlice("subSlice", slice[3:])

// slice can also be created from an array
arr := [...]int{11, 22, 33, 44, 55}
arrSlice := arr[:3]
printSlice("arrSlice", arrSlice)

// slice can also be dynamically created with make([]T, size, cap)
madeSlice := make([]int, 8, 16)
printSlice("makeSlice", madeSlice)

// slice can be copied from src slice to dest slice
copy(madeSlice, slice)
printSlice("copiedSlice", madeSlice)
}

func printSlice(tag string, slice []int) {
fmt.Printf("%s: date = %v, len = %d, cap = %d, addr = %p\n", tag, slice, len(slice), cap(slice), &slice)
}


10 列表list

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

import (
"container/list"
"fmt"
)

// run with commands:
// go run src\10_list.go

// list.List in go is a doubly linked list

func main() {
// create a list
numsList := list.New()

// append elements to list with PushBack
for i := 1; i < 10; i++ {
numsList.PushBack(i)
}
printList(numsList)

// add elements to front with PushFront
first := numsList.PushFront(0)
printList(numsList)

// elements can be removed
numsList.Remove(first)
printList(numsList)
}

func printList(srcList *list.List) {
for node := srcList.Front(); node != nil; node = node.Next() {
fmt.Print(node.Value, " ")
}
fmt.Println()
}

11 字典map

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

import "fmt"

// run with commands:
// go run src\11_map.go

func main() {
// create a map
emptyMap := map[string]string{}
printMap(emptyMap)

// create and init a map
city2id := map[string]string{
"Suzhou": "0512",
"Beijing": "010",
"Shanghai": "021",
}
printMap(city2id)

// create a map with make(type)
id2city := make(map[string]string)

id2city["0512"] = "Suzhou"
id2city["010"] = "Beijing"
id2city["021"] = "Shanghai"

fmt.Printf("Query: 010, Result: %s\n", id2city["010"])
printMap(id2city)
}

func printMap(srcMap map[string]string) {
fmt.Printf("len = %d\n", len(srcMap))
for k, v := range srcMap {
fmt.Println(k, v, " ")
}
fmt.Println()
}

12 函数func

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

import (
"fmt"
"time"
)

// run with commands:
// go run src\12_func.go

/*
A standard paradigm of function in go:

func func_name(inputParams) (returnParams) {
func body
}
*/

// a func with multiple inputs and single output
func add(x, y int) int {
return x + y
}

// a func with multiple inputs and multiple outputs
// return values can be named
func div(dividend, divisor int) (quotient, remainder int) {
quotient = dividend / divisor
remainder = dividend % divisor
return
}

func addMul(x, y int) (int, int) {
vAdd := x + y
vMul := x * y
return vAdd, vMul
}

// a function with input but no return value
func echo(s string) {
fmt.Println(s)
}

// input a func as a callback func
func traverse(arr []int, handler func(num int)) {
for _, v := range arr {
handler(v)
}
}

// pass a pointer to func
func increase(x *int) {
*x = 2
}

func main() {
// call a named function
fmt.Println(add(1, 2))
fmt.Println(div(8, 5))
fmt.Println(addMul(2, 3))
echo("Hello, world!")

// define and call an anonymous func
vMul := func(x, y int) int {
return x - y
}(1, 2)
fmt.Println(vMul)

curTime := func() {
fmt.Println(time.Now())
}
curTime()

// use an anonymous func as callback function
arr := []int{1, 2, 3, 4, 5}
traverse(arr, func(num int) {
fmt.Print(num*num, " ")
})
fmt.Println()

// pass num to func by its pointer
vNum := 1
fmt.Println("Before: ", vNum)
increase(&vNum)
fmt.Println("After: ", vNum)
}

13 闭包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
29
30
31
package main

import "fmt"

// run with commands:
// go run src\13_closure.go

// closure is a function carrying state

func createCounter(initial int) func() int {
if initial < 0 {
initial = 0
}

return func() int {
initial++
return initial
}
}

func main() {
counter1 := createCounter(0)
fmt.Println(counter1()) // 1
fmt.Println(counter1()) // 2

counter2 := createCounter(10)
fmt.Println(counter2()) // 11

fmt.Println(counter1()) // 3
}

14 结构体struct

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

import "fmt"

// run with commands:
// go run src\14_struct.go

/*
struct can be defined in paradigm:

type structName struct {
value1 valueType1
value2 valueType2
...
}
*/

type Person struct {
Name string
Birth string
ID uint64
}

func main() {
// declare a struct variable
var person1 Person
person1.Name = "Mike"
person1.Birth = "1990-1-2"
person1.ID = 1
fmt.Println(person1)

// new a struct variable
person2 := new(Person) // person2 is a pointer
person2.Name = "Tom"
person2.Birth = "1991-2-3"
person2.ID = 2
fmt.Println(person2)

// another way to new a person with empty initial values
person3 := &Person{} // person3 is a pointer
person3.Name = "Nancy"
person3.Birth = "1992-3-4"
person3.ID = 3
fmt.Println(person3)

// create an object with initial values
person4 := Person{
Name: "Jack",
Birth: "1993-4-5",
ID: 4,
}
fmt.Println(person4)

person5 := &Person{ // person5 is a pointer
Name: "John",
Birth: "1994-5-6",
ID: 5,
}
fmt.Println(person5)
}

15 方法method

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

import "fmt"

// run with commands:
// go run src\15_method.go

/*
In go, method is a function with recipient.
Recipient can be any type, typically a struct, which means any type in
go can have its methods.

Method can be defined in paradigm:

func (recipient RecipientType) methodName(inputParams) (returnParams) {
func body
}
*/

type Student struct {
Name string
Age uint8
ID uint64
}

// modify student's name with pointer to the instance
func (student *Student) setName(name string) {
student.Name = name
}

// non-pointer, unable to modify the original instance
func (student Student) badSet(name string) {
student.Name = name
}

func (student Student) print() {
fmt.Printf("Student %s (ID: %v) is %v years old.\n",
student.Name, student.ID, student.Age)
}

func main() {
student1 := Student{
Name: "Jack",
Age: 12,
ID: 1,
}

student1.print()

student1.badSet("Little Jack")
student1.print()

student1.setName("Big Jack")
student1.print()
}

16 接口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
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
package main

import "fmt"

// run with commands:
// go run src\16_interface1.go

/*
standard interface paradigm:

type interfaceName interface {
func1(inputParams) (returnParams)
func2(inputParams) (returnParams)
func3(inputParams) (returnParams)
}

If the interfaceName is in uppercase, its a public interface.
If the function name is in uppercase, its a public function.
A public function can be accessed outside of the package,
otherwise, non-public function can only be accessed inside of
the package.
*/

type Cat interface {
CatchMouse()
}

type Dog interface {
Bark()
}

type CatDog struct {
Name string
}

// type CatDog implements functions in interface Cat
func (catDog *CatDog) CatchMouse() {
fmt.Printf("%s is catching mice!\n", catDog.Name)
}

// type CatDog implements functions in interface Dog
func (catDog *CatDog) Bark() {
fmt.Printf("%s is barking!\n", catDog.Name)
}

func main() {
// catDog is a pointer to CatDog instance
catDog := &CatDog{
Name: "Tom",
}

// declare Cat interface and point to CatDog type
var cat Cat
cat = catDog
cat.CatchMouse()

// declare Dog interface and point to CatDog type
var dog Dog
dog = catDog
dog.Bark()
}

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

import "fmt"

// run with commands:
// go run src\16_interface2.go

/*
standard interface paradigm:

type interfaceName interface {
func1(inputParams) (returnParams)
func2(inputParams) (returnParams)
func3(inputParams) (returnParams)
}

If the interfaceName is in uppercase, its a public interface.
If the function name is in uppercase, its a public function.
A public function can be accessed outside of the package,
otherwise, non-public function can only be accessed inside of
the package.
*/

type Printer interface {
Print(interface{})
}

type FuncCaller func(p interface{})

func (funcCaller FuncCaller) Print(p interface{}) {
funcCaller(p)
}

func main() {
// Printer is the abstraction of printer
// FuncCaller func is the implementation of printer
// printer can call Printer.Print implemented by FuncCaller's Print
var printer Printer
printer = FuncCaller(func(p interface{}) {
fmt.Println(p)
})
// cast an anonymous function to FuncCaller type
// then printer calls Print implemented by FuncCaller
printer.Print("Golang is Good!")
}

17 嵌入embedding

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

import "fmt"

// run with commands:
// go run src\16_interface2.go

/*
struct can embed anonymous attributes (type-only) to implement composition relation.

standard embedded struct type paradigm:

type A struct {
typeB
typeC
}
*/

type Swimming struct {
}

func (swim *Swimming) swim() {
fmt.Println("swimming")
}

type Flying struct {
}

func (flying *Flying) fly() {
fmt.Println("flying")
}

// Wild Duck can swim and fly
type WildDuck struct {
Swimming
Flying
}

// Domestic Duck can only swim
type DomesticDuck struct {
Swimming
}

func main() {
wildDuck := WildDuck{}
wildDuck.fly()
wildDuck.swim()

domesticDuck := DomesticDuck{}
domesticDuck.swim()
}