这是github上翻译的文章,没有翻译全,不过内容还是很不错的,值得一看。
第一章 输入输出
fmt-格式化IO
1.Print 序列函数
- Fprint/Fprintf/Fprintln 函数的第一个参数接收一个io.Writer类型,会将内容输出到 io.Writer 中去
- Sprint/Sprintf/Sprintln 是格式化内容为 string 类型,而并不输出到某处,需要格式化字符串并返回时,可以用这组函数
- Print/Printf/Println 函数是将内容输出到标准输出中,因此,直接调用 F类函数 做这件事,并将 os.Stdout 作为第一个参数传入
2.Scan 序列函数
- Fscan/Fscanf/Fscanln 函数的第一个参数接收一个 io.Reader 类型,从其读取内容并赋值给相应的实参
- Scan/Scanf/Scanln 正是从标准输入获取内容,因此,直接调用 F类函数 做这件事,并将 os.Stdin 作为第一个参数传入
- Sscan/Sscanf/Sscanln 则直接从字符串中获取内容
3.递归转换
若一个操作数实现了 error 接口,Error 方法就能将该对象转换为字符串,随后会根据占位符的需要进行格式化。
若一个操作数实现了 String() string 方法,该方法能将该对象转换为字符串,随后会根据占位符的需要进行格式化。
为避免以下这类递归的情况: type X string func (x X) String() string { return Sprintf(“<%s>”, x) }
需要在递归前转换该值: func (x X) String() string { return Sprintf(“<%s>”, string(x)) }
第二章 文本
strings-字符串操作
-
1
2
3
4
5// chars 中任何一个 Unicode 代码点在 s 中,返回 true
func ContainsAny(s, chars string) bool
//第二个参数 chars 中任意一个字符(Unicode Code Point)如果在第一个参数 s 中存在,则返回 true。
fmt.Println(strings.ContainsAny("failure", "u & i"))
//true
2.在 Go 中,查找子串出现次数即字符串模式匹配,实现的是 Rabin-Karp 算法。Count 是计算子串在字符串中出现的无重叠的次数,比如fmt.Println(strings.Count(“fivevev”, “vev”)),输出1
strconv — 字符串和基本数据类型之间转换
1 | package main |
unicode — Unicode 码点、UTF-8/16 编码
1.UTF-8 表示最少用一个字节就能表示一个字符的编码实现。英文占一个字节,中文占三个字节。
2.UTF-16 表示最少用两个字节能表示一个字符的编码实现。英文占用两个字节,中文占用两个或者四个字节。
3.rune: 可以用来计算字符串字符长度,而不是byte的长度
1 | //int32的别名,几乎在所有方面等同于int32 |
第三章 数据结构与算法
sort —— 排序算法
1.该包实现了四种基本排序算法:插入排序、归并排序、堆排序和快速排序。 sort 包会根据实际数据自动选择高效的排序算法。
第四章 日期与时间
1.时间戳转时间
1 | fmt.Println(time.Unix(1389058332, 0).Format("2006-01-02 15:04:05")) //2014-01-07 09:32:12 |
2.时间转时间戳
1 | fmt.Println(time.Date(2014, 1, 7, 5, 50, 4, 0, time.Local).Unix()) |
3.定时器
两种定时器:Timer
(到达指定时间触发且只触发一次)和 Ticker
(间隔特定时间触发)
4.Timer的具体实现逻辑,通过四叉树堆 (heep) 实现的(runtimeTimer
结构中的 i
字段,表示在堆中的索引)。通过构建一个最小堆,保证最快拿到到期了的定时器执行。定时器的执行,在专门的 goroutine
中进行的:go timerproc()
。
5.无缓冲 channel,发送者会阻塞直到接收者接收了发送的值。
第六章 文件系统
1.File的Write
调用成功并不能保证数据已经写入磁盘,因为内核会缓存磁盘的 I/O 操作。如果希望立刻将数据写入磁盘(一般场景不建议这么做,因为会影响性能),有两种办法:
1 | 1. 打开文件时指定 `os.O_SYNC`; |
2.我们应该养成关闭不需要的文件的良好编程习惯。文件描述符是资源,Go 的 gc 是针对内存的,并不会自动回收资源,如果不关闭文件描述符,长期运行的服务可能会把文件描述符耗尽。
第九章 测试
1.单元测试步骤
- 创建一个名称以 _test.go 结尾的文件
- 包含
TestXxx
函数 - 执行
go test .
1 | func TestFib(t *testing.T) { |
2.包中的 Parallel 方法表示当前测试只会与其他带有 Parallel 方法的测试并行进行测试。
3.测试用例有四种形式:
1 | TestXxxx(t *testing.T) // 基本测试用例 |
4.如果测试文件中包含TestMain(m)
,那么生成的测试将调用 TestMain(m)
,而不是直接运行测试。
第十章 进程、线程和 goroutine
线程
1.在 Linux 中,通过系统调用 clone()
来实现线程的。
2.父子俩共享了地址空间 (_CLONE_VM)、文件系统资源 (_CLONE_FS)、文件描述符 (_CLONE_FILES) 和信号处理程序 (_CLONE_SIGHAND)。而 _CLONE_THREAD
则会将父子进程放入相同的线程组。这样一来,新建的进程和父进程都叫做线程。
进程
1.在 Unix 中,创建一个进程,通过系统调用 fork
实现(及其一些变种,如 vfork、clone)。在 Go 语言中,Linux 下创建进程使用的系统调用是 clone
。
2.4个系统调用及其典型用法。
- fork:允许一进程(父进程)创建一新进程(子进程)。具体做法是,新的子进程几近于对父进程的翻版:子进程获得父进程的栈、数据段、堆和执行文本段的拷贝。可将此视为把父进程一分为二。
- exit(status):终止一进程,将进程占用的所有资源(内存、文件描述符等)归还内核,交其进行再次分配。参数
status
为一整型变量,表示进程的退出状态。父进程可使用系统调用wait()
来获取该状态。 - wait(&status) 目的有二:其一,如果子进程尚未调用
exit()
终止,那么wait
会挂起父进程直至子进程终止;其二,子进程的终止状态通过wait
的status
参数返回。 - execve(pathname, argv, envp) 加载一个新程序(路径名为 pathname,参数列表为 argv,环境变量列表为 envp)到当前进程的内存。这将丢弃现存的程序文本段,并为新程序重新创建栈、数据段以及堆。通常将这一动作称为执行一个新程序。