0%

go in action

本文主要记录了阅读 go in action 的笔记

Chapter 2 & 3 Packaging and tooling

程序执行的顺序

1
2
3
4
func init() {
}
func main() {
}

初始化一个 go 项目

现在都要使用 go mod,不需要用 GOPATH 之类的

首先要在相应项目下初始化,如

1
go mod init github.com/goinaction/code/chapter2/sample

然后

1
go mod tidy

来清理和更新模块的依赖。如果代码中使用了某些包,但这些包没有在 go.mod 中列出,go mod tidy 会自动添加它们

make(map[string]Matcher)

  • 如果你只是声明一个 map 而不初始化(即 var m map[string]int),那么 m 的值是 nil。在这种情况下,尝试向 m 中添加键值对会导致运行时错误(panic)。
  • 使用 make 或字面量初始化 map 可以确保 map 是非 nil 的,并且可以安全地添加键值对。

import

1
2
3
import (
_ "github.com/lib/pq" // 空白导入(仅初始化)
)

go vet

错误检查

go fmt

格式化

go mod vendor

自动把依赖的第三方包拷贝到 vendor 目录下

★ 安装指定版本的 go//官方推荐做法

比如我们已经有了 1.23,想要装 1.16

1
go install golang.org/dl/go1.16@latest
1
go1.16 download

这样要使用 1.16 的话,把所有的 go version 这样的命令的 go 换成 go1.16 就可以了

Chapter 4 Arrays, slices, and maps

Arrays, slices

1
2
3
4
5
6
7
8
9
10
11
// 数组
var arr [5]int // 声明一个长度为5的整型数组
arr := [3]int{1, 2, 3} // 声明并初始化
arr2 := [...]int{1, 2, 3}

// 切片
var slice []int // 声明一个整型切片
slice := []int{1, 2, 3} // 声明并初始化
slice := make([]int, 5) // 使用make创建切片

//区别是定长和不定长

切片的常用操作和方法:

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
// 1. 声明和初始化
slice1 := []int{1, 2, 3} // 直接初始化
slice2 := make([]int, 3, 5) // 使用make创建
var slice3 []int // 声明空切片

// 2. 获取长度和容量
length := len(slice1)
capacity := cap(slice1)

// 3. append - 添加元素
slice1 = append(slice1, 5, 6, 7) // 添加多个元素
slice1 = append(slice1, slice2...) // 添加另一个切片的所有元素

// 4. copy - 复制切片
slice4 := make([]int, len(slice1))
copy(slice4, slice1)

// 5. 切片截取
slice5 := slice1[1:3] // 包含开始索引,不包含结束索引

// 6. 遍历
for i := 0; i < len(slice1); i++ {
fmt.Println(slice1[i])
}

for index, value := range slice1 {
fmt.Printf("index: %d, value: %d\n", index, value) //别忘了要把索引去掉
}

// 9. 删除元素
// 从切片中删除索引为i的元素
i := 2
slice1 = append(slice1[:i], slice1[i+1:]...)

// 10. 插入元素
// 在索引i处插入元素x
i := 2
x := 10
slice1 = append(slice1[:i], append([]int{x}, slice1[i:]...)...)

常用的工具包操作:

1
2
3
4
5
6
7
8
9
10
11
12
import "sort"

// 1. 排序
sort.Ints(slice1) // 整数切片排序
sort.Float64s(floatSlice) // 浮点数切片排序
sort.Strings(stringSlice) // 字符串切片排序

// 2. 搜索(要求切片已排序)
index := sort.SearchInts(slice1, 5) // 二分查找

// 3. 判断是否已排序
isSorted := sort.IntsAreSorted(slice1) // 检查是否已排序

一些实用技巧:

1
2
3
4
5
6
7
8
9
10
11
// 1. 预分配容量以提高性能
slice := make([]int, 0, 1000)

// 2. 截取时指定容量
slice = slice[:20:20] // 第三个参数限制容量

// 3. 使用copy而不是re-slice来避免内存泄漏
b := make([]byte, 100)
b1 := b[:50]
b2 := make([]byte, len(b1))
copy(b2, b1) // 避免引用大数组

注意切片容量和长度的概念

map

初始化

1
2
3
4
5
6
7
8
9
10
11
12
// 方式1:使用 make
map1 := make(map[string]int)

// 方式2:字面量声明
map2 := map[string]int{
"apple": 1,
"banana": 2,
}

// 方式3:声明空map
var map3 map[string]int
map3 = make(map[string]int) // 需要先初始化才能使用,不然会有RE

基本操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 添加或修改元素
map1["apple"] = 1

// 获取元素
value := map1["apple"]

// 删除元素
delete(map1, "apple")

// 检查键是否存在
value, exists := map1["apple"]
if exists {
fmt.Println("键存在,值为:", value)
} else {
fmt.Println("键不存在")
}

// 获取map长度
length := len(map1)

遍历 map:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 遍历所有键值对
for key, value := range map1 {
fmt.Printf("key: %s, value: %d\n", key, value)
}

// 只遍历键
for key := range map1 {
fmt.Printf("key: %s\n", key)
}

// 只遍历值
for _, value := range map1 {
fmt.Printf("value: %d\n", value)
}

Chapter 5 Go’s type system

Reference types

slice, map, channel, interface, and function types

不需要共享引用类型值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 使用切片举例
func modifySlice(s []int) {
s[0] = 100 // 直接修改底层数据
}

func main() {
slice := []int{1, 2, 3}

// 不需要这样写:
// modifySlice(&slice) // ❌ 不需要传递指针

// 正确的方式:
modifySlice(slice) // ✅ 直接传递切片

fmt.Println(slice) // 输出 [100, 2, 3]
}