Golang笔记。

Ref

语法

basics

if

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import "fmt"

func main() {
	var number int = 5
	if number += 6; 10 > number {

		number += 3
		fmt.Print(number)
	} else if 10 < number {
		number -= 2
		fmt.Print(number)
	}
	fmt.Println(number)
}

defer

 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
import (
	"fmt"
	"io/ioutil"
	"os"
)

func main() {
	bytes, err := readFile("README.md")
	if err != nil {
		panic(err)
	}
	for _, v := range bytes {
		fmt.Println(v)
	}

	deferIt()

	deferIt2()

	deferIt3()

	deferIt4()

	for i := 0; i < 10; i++ {
		defer func(n int) {
			// 后执行
			fmt.Printf("%d ", n)
		}(func() int {
			// 调用即求值
			n := fibonacci(i)
			fmt.Printf("%d ", n)
			return n
		}())
	}
}

func readFile(path string) ([]byte, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	return ioutil.ReadAll(file)
}

func deferIt() {
	defer func() {
		fmt.Print(1)
	}()
	defer func() {
		fmt.Print(2)
	}()
	defer func() {
		fmt.Print(3)
	}()
	fmt.Print(4)
}

func deferIt2() {
	for i := 1; i < 5; i++ {
		defer fmt.Println(i)
	}
}

func deferIt3() {
	f := func(i int) int {
		fmt.Printf("%d ", i)
		return i * 10
	}

	for i := 1; i < 5; i++ {
		// Possible resource leak, 'defer' is called in a for loop less... (⌃F1)
		// Inspection info: Reports defer statements inside loops.
		// 调用匿名函数的时候就已经进行了内部的执行
		defer fmt.Printf("%d ", f(i))
	}
}

func deferIt4() {
	for i := 1; i < 5; i++ {
		// 语句携带的表达式语句中的那个匿名函数包含了对外部(确切地说,是该defer语句之外)的变量的使用。
		// 注意,等到这个匿名函数要被执行(且会被执行4次)的时候,包含该defer语句的那条for语句已经执行完毕了。此时的变量i的值已经变为了5
		defer func() {
			fmt.Println(i)
		}()
	}
}

func fibonacci(num int) int {
	if num == 0 {
		return 0
	}
	if num < 2 {
		return 1
	}
	return fibonacci(num-1) + fibonacci(num-2)
}

error

 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
import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
)

func innerFunc() {
	fmt.Println("Enter innerFunc")
	defer withRecover()
	panic(errors.New("Occur a panic!"))
	fmt.Println("Quit innerFunc")

}

func outerFunc() {
	fmt.Println("Enter outerFunc")
	innerFunc()
	fmt.Println("Quit outerFunc")
}

func main() {
	fmt.Println("Enter main")
	outerFunc()
	fmt.Println("Quit main")
}

func readFile(path string) ([]byte, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	return ioutil.ReadAll(file)
}

func withRecover() {
	if p := recover(); p != nil {
		fmt.Printf("error msg: %s", p)
	}
}

for

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import "fmt"

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

	// 遍历字符串
	for i, v := range "Go语言" {
		fmt.Printf("%d: %c\n", i, v)
	}

	map1 := map[int]string{1: "Golang", 2: "Java", 3: "Python", 4: "C"}
	for i, v := range map1 {
		fmt.Printf("%d: %s \n", i, v)
	}
}

goroutine

 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
import (
	"fmt"
	"runtime"
	"sync"
)

func main() {
	gosched()

	waitGroup()
}

func waitGroup() {
	// 异步转同步,类似于Java中的CountDownLatch
	var wg sync.WaitGroup
	wg.Add(3)
	go func() {
		fmt.Println("Go!")
		wg.Done()
	}()
	go func() {
		fmt.Println("Go!")
		wg.Done()
	}()
	go func() {
		fmt.Println("Go!")
		wg.Done()
	}()
	wg.Wait()
}

func gosched() {
	go fmt.Println("Goroutine!")
	// 让当前正在运行的Goroutine(这里是运行main函数的那个Goroutine)暂时“休息”一下
	runtime.Gosched()
}

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

type Animal interface {
	Grow()
	Move(start string) string
}

type Cat struct {
	Name   string
	Age    uint8
	Gender string
	Start  string
	End    string
}

func (cat *Cat) Grow() {
	cat.Age++
}

func (cat *Cat) Move(start string) string {
	fmt.Printf("cat move from %s name: %s", start, cat.Name)
	return "cat move result"
}

func main() {
	myCat := Cat{Name: "Little C", Age: 2, Gender: "Male"}
	animal, ok := interface{}(&myCat).(Animal)
	fmt.Printf("%v, %v\n", ok, animal)
}

// func(dog *Dog) Name() string{
//    return dog.Name
//}
//func(dog *Dog) Age() uint8{
//    return dog.Age
//}

iota

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

func main() {
	// iota在const关键字出现时将被重置为0
	const cons1 = iota
	const cons2 = iota

	fmt.Println(cons1)
	fmt.Println(cons2)

	// const中每新增一行常量声明将使iota计数一次
	const (
		cons3 = iota
		// 跳值
		_
		// 插值
		cons4 = 666
		_
		cons5 = iota + 2
		// 隐式赋值
		cons6
		cons7

		cons8, cons9 = iota, iota + 2
		cons10, cons11
	)
	fmt.Println(cons3)
	fmt.Println(cons4)
	fmt.Println(cons5)
	fmt.Println(cons6)
	fmt.Println(cons7)

	fmt.Println(cons8)
	fmt.Println(cons9)
	fmt.Println(cons10)
	fmt.Println(cons11)
}

pointer

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

type MyInt struct {
	n int
}

// 修改结构体中属性值时,使用指针类型传递
func (myInt *MyInt) Increase() {
	myInt.n++
}

func (myInt MyInt) Decrease() {
	myInt.n--
}

type Pet interface {
	Name() string
	Age() uint8
}

type Dog struct {
	name string
	age  uint8
}

// 返回结构体中属性值时,直接用值类型传参
func (dog Dog) Name() string {
	return dog.name
}
func (dog Dog) Age() uint8 {
	return dog.age
}

func main() {
	mi := MyInt{}
	mi.Increase()
	mi.Increase()
	mi.Decrease()
	mi.Decrease()
	mi.Increase()
	fmt.Printf("%v\n", mi.n == 3)

	// =======
	myDog := Dog{"Little D", 3}
	_, ok1 := interface{}(myDog).(Pet)
	_, ok2 := interface{}(&myDog).(Pet)
	fmt.Printf("%v, %v\n", ok1, ok2)
}

select

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

func main() {
	// select语句属于条件分支流程控制方法,
	// 不过它只能用于通道。
	// 它可以包含若干条case语句,
	// 并根据条件选择其中的一个执行。
	// 进一步说,select语句中的case关键字只能后跟用于通道的发送操作的表达式以及接收操作的表达式或语句。示例如下:
	ch1 := make(chan int, 1)
	ch2 := make(chan int, 1)
	// 省略若干条语句
	select {
	case e1 := <-ch1:
		fmt.Printf("1th case is selected. e1=%v.\n", e1)
	case e2 := <-ch2:
		fmt.Printf("2th case is selected. e2=%v.\n", e2)
	default:
		fmt.Println("No data!")
	}

	// 另一方面,对于包含通道发送操作的case来讲,
	// 其执行条件就是通道中至少还能缓冲一个数据(或者说通道未满)。
	// 类似的,当有多个case中的通道未满时,它们会被随机选择。请看下面的示例:
	ch3 := make(chan int, 100)
	select {
	case ch3 <- 1:
		fmt.Printf("Sent %d\n", 1)
	case ch3 <- 2:
		fmt.Printf("Sent %d\n", 2)
	default:
		fmt.Println("Full channel!")
	}

	ch4 := make(chan int, 1)
	for i := 0; i < 4; i++ {
		select {
		case e, ok := <-ch4:
			if !ok {
				fmt.Println("End.")
				return
			}
			fmt.Println(e)
			// 操作完关闭channel
			close(ch4)
		default:
			fmt.Println("No Data!")
			// 发数据到channel
			ch4 <- 1
		}
	}
}

switch

 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
import (
	"fmt"
	"math/rand"
)

func main() {
	var name string = "Golang"
	switch name {
	case "Golang":
		fmt.Println("A programming language from Google.")
	case "Rust":
		fmt.Println("A programming language from Mozilla.")
	default:
		fmt.Println("Unknown!")
	}

	// 类型switch
	ia := []interface{}{byte(6), 'a', uint(10), int32(-4)}
	intn := rand.Intn(4)
	fmt.Println(intn)
	switch v := ia[intn]; interface{}(v).(type) {
	// rune is an alias for int32 and is equivalent to int32 in all ways. It is
	// used, by convention, to distinguish character values from integer values.
	case rune:
		fmt.Printf("Case A.")
	case byte:
		fmt.Printf("Case B.")
	default:
		fmt.Println("Unknown!")
	}

}

cmd

concurrent-channel

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

func main() {
	// 通过channel通信
	ch := make(chan string)
	// 开启goroutine
	go printConcurrent(666, ch)

	// 开启多个协程
	// := 声明赋值
	for i := 0; i < 5; i++ {
		// ch获取输入
		go printConcurrent(i, ch)
	}

	// ch读取输出
	for {
		msg := <-ch
		fmt.Println(msg)
	}

	// 休眠保留运行
	//time.Sleep(time.Millisecond * 3)
}

func printConcurrent(i int, ch chan string) {
	for {
		ch <- fmt.Sprintf("Hello Concurrent Go %d \n", i)
	}
}

pipeline

  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
import (
	"encoding/binary"
	"io"
	"math/rand"
	"sort"
)

// empty file:不包括main(),用于他方调用的库编码

// 接收一个int数组,扔进channel,返回
func ArraySource(srcArr ...int) chan int {
	// 创建channel
	out := make(chan int)
	// channel内容只能通过goroutine进行传送
	go func() {
		for _, v := range srcArr {
			// 数组内容扔进channel
			out <- v
		}

		// 关闭通道
		close(out)
	}()

	return out
}

// 增加<- 表示只进不出
func ArraySource2(srcArr ...int) <-chan int {
	out := make(chan int)
	go func() {
		for _, v := range srcArr {
			out <- v
		}
		close(out)
	}()
	return out
}

// 内存排序
func InMemorySort(in <-chan int) <-chan int {
	out := make(chan int, 1024)
	go func() {
		arr := []int{}
		// 输入的chan,读取内容到slice中
		for v := range in {
			arr = append(arr, v)
		}

		// 排序
		sort.Ints(arr)

		// 扔进chan
		for _, v := range arr {
			out <- v
		}
		close(out)
	}()
	return out
}

// 合并节点,归并操作
func Merge(in1, in2 <-chan int) <-chan int {
	out := make(chan int, 1024)

	go func() {
		v1, ok1 := <-in1
		v2, ok2 := <-in2

		// 接收方:ok判定有无元素
		for ok1 || ok2 {
			// in2无值取in1
			// in1中有值,且小于in2中的值
			if !ok2 || (ok1 && v1 < v2) {
				// 将v1扔进out
				out <- v1
				// 继续读in1
				v1, ok1 = <-in1

			} else {
				// 将v2扔进out
				out <- v2
				// 继续读in2
				v2, ok2 = <-in2
			}
		}

		// 发送方:channel关闭
		close(out)
	}()

	return out
}

// 归并多个节点
func MergeN(inputs ...<-chan int) <-chan int {
	size := len(inputs)
	if size == 1 {
		return inputs[0]
	}
	middle := size / 2

	return Merge(MergeN(inputs[:middle]...), MergeN(inputs[middle:]...))
}

// 文件系统读取源数据
func ReaderSource(reader io.Reader, chunkSize int) <-chan int {
	out := make(chan int, 1024)

	go func() {
		// 指定八位
		buffer := make([]byte, 8)
		// 已读的字节数
		bytesRead := 0

		for {
			// 读到的字节数
			n, err := reader.Read(buffer)
			bytesRead += n
			if n > 0 {
				// 转换文件字节到channel
				out <- int(binary.BigEndian.Uint64(buffer))
			}

			// 处理错误
			// 超出了预设的块大小
			exceedChunk := chunkSize != -1 && chunkSize <= bytesRead
			if err != nil || exceedChunk {
				break
			}
		}

		close(out)
	}()

	return out
}

// 写数据
func WriterSink(writer io.Writer, in <-chan int) {
	for v := range in {
		buffer := make([]byte, 8)

		binary.BigEndian.PutUint64(buffer, uint64(v))

		_, err := writer.Write(buffer)
		if err != nil {
			panic(err)
		}
	}
}

// 生成随机数据源
func RandomSource(count int) <-chan int {
	out := make(chan int)

	go func() {
		for i := 0; i < count; i++ {
			out <- rand.Int()
		}

		close(out)
	}()

	return out
}

sort

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

func main() {
	// 初始化一个int类型的slice
	intSlice := []int{
		1, 3, 9, 2, 4,
	}
	fmt.Println(intSlice)

	// 调用库排序
	sort.Ints(intSlice)

	fmt.Println(intSlice)

	// for range
	for index, value := range intSlice {
		fmt.Println(index, value)
	}

	fmt.Println("===============")
	// 不使用变量时,用_声明
	for _, value := range intSlice {
		fmt.Println(value)
	}
}

sort-external

 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
import (
	"bufio"
	"fmt"
	"hello-go/pipeline"
	"os"
)

func main() {
	p := createPipeline("small.in", 512, 4)

	writeToFile(p, "small.out")

	printFile("small.out")
}

func printFile(fileName string) {
	file, err := os.Open(fileName)

	if err != nil {
		panic(err)
	}
	defer file.Close()

	p := pipeline.ReaderSource(file, -1)
	for v := range p {
		fmt.Println(v)
	}

}

func writeToFile(p <-chan int, fileName string) {
	file, err := os.Create(fileName)

	if err != nil {
		panic(err)
	}

	defer file.Close()

	writer := bufio.NewWriter(file)
	defer writer.Flush()

	pipeline.WriterSink(writer, p)
}

func createPipeline(fileName string, fileSize, chunkCount int) <-chan int {
	chunkSize := fileSize / chunkCount

	sortResults := []<-chan int{}

	for i := 0; i < chunkCount; i++ {
		file, err := os.Open(fileName)
		if err != nil {
			panic(err)
		}

		file.Seek(int64(i*chunkSize), 0)

		source := pipeline.ReaderSource(bufio.NewReader(file), chunkSize)

		sortResults = append(sortResults, pipeline.InMemorySort(source))
	}

	return pipeline.MergeN(sortResults...)
}


pipeline-demo

 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
import (
	"bufio"
	"fmt"
    // 上面pipeline中实现了内存排序、归并操作
	"hello-go/pipeline"
	"os"
)

const (
	fileName = "small.in"
	count    = 50
)

func main() {

	//const FILE_NAME = "small.in"
	//const count = 50

	//testMerge()

	file, err := os.Create(fileName)
	if err != nil {
		panic(err)
	}
	defer file.Close()

	randomSrc := pipeline.RandomSource(count)
	writer := bufio.NewWriter(file)
	pipeline.WriterSink(writer, randomSrc)
	writer.Flush()

	file, err = os.Open(fileName)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	// 逐行处理文件
	reader := bufio.NewReader(file)
	fileCh := pipeline.ReaderSource(reader, -1)
	for v := range fileCh {
		fmt.Println(v)
	}
}

func testMerge() {
	ch1 := pipeline.ArraySource2(3, 1, 4, 2, 66)
	ch2 := pipeline.ArraySource2(4, 2, 5, 3, 77)
	// 排序
	sortedCh1 := pipeline.InMemorySort(ch1)
	sortedCh2 := pipeline.InMemorySort(ch2)
	mergedCh := pipeline.Merge(sortedCh1, sortedCh2)
	//for ; ; {
	//	// ok表示source channel还未关闭
	//	// 该写法不易读
	//	if v, ok := <-ch1; ok {
	//		fmt.Println(v)
	//	} else {
	//		break
	//	}
	//}
	// 直接用for range,提高可读性
	for v := range mergedCh {
		fmt.Println(v)
	}
}

web

web-server

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
		fmt.Fprintf(writer, "<h1>Hello Golang: %s</h1>", request.FormValue("name"))
	})

	serve := http.ListenAndServe(":8080", nil)

	if serve == nil {
		fmt.Print(serve)
	}
}