1
0
mirror of https://github.com/chai2010/advanced-go-programming-book.git synced 2025-05-24 04:22:22 +00:00

ch1: 规范图像文件编号

This commit is contained in:
chai2010 2018-12-14 21:35:56 +08:00
parent dbd8324a0b
commit 639aa04aab
25 changed files with 26 additions and 26 deletions

View File

@ -4,9 +4,9 @@ Go语言最初由Google公司的Robert Griesemer、Ken Thompson和Rob Pike三个
Go语言很多时候被描述为“类C语言”或者是“21世纪的C语言”。从各种角度看Go语言确实是从C语言继承了相似的表达式语法、控制流结构、基础数据类型、调用参数传值、指针等诸多编程思想还有彻底继承和发扬了C语言简单直接的暴力编程哲学等。图1-1是《Go语言圣经》中给出的Go语言的基因图谱我们可以从中看到有哪些编程语言对Go语言产生了影响。
![](../images/ch1.1-1-go-family-tree.png)
![](../images/ch1-1-go-family-tree.png)
*图 1.1-1 Go语言基因族谱*
*图 1-1 Go语言基因族谱*
首先看基因图谱的左边一支。可以明确看出Go语言的并发特性是由贝尔实验室的Hoare于1978年发布的CSP理论演化而来。其后CSP并发模型在Squeak/NewSqueak和Alef等编程语言中逐步完善并走向实际应用最终这些设计经验被消化并吸收到了Go语言中。业界比较熟悉的Erlang编程语言的并发编程模型也是CSP理论的另一种实现。
@ -24,17 +24,17 @@ CSP并发模型最经典的实际应用是来自爱立信发明的Erlang编程
图1-2展示了Go语言库早期代码库日志可以看出最直接的演化历程Git用`git log --before={2008-03-03} --reverse`命令查看)。
![](../images/ch1.1-2-go-log4.png)
![](../images/ch1-2-go-log4.png)
*图 1.1-2 Go语言开发日志*
*图 1-2 Go语言开发日志*
从早期提交日志中也可以看出Go语言是从Ken Thompson发明的B语言、Dennis M. Ritchie发明的C语言逐步演化过来的它首先是C语言家族的成员因此很多人将Go语言称为21世纪的C语言。
图1-3是Go语言中来自贝尔实验室特有并发编程基因的演化过程
![](../images/ch1.1-3-go-history.png)
![](../images/ch1-3-go-history.png)
*图 1.1-3 Go语言并发演化历史*
*图 1-3 Go语言并发演化历史*
纵观整个贝尔实验室的编程语言的发展进程从B语言、C语言、Newsqueak、Alef、Limbo语言一路走来Go语言继承了来着贝尔实验室的半个世纪的软件设计基因终于完成了C语言革新的使命。纵观这几年来的发展趋势Go语言已经成为云计算、云存储时代最重要的基础编程语言。

View File

@ -2,9 +2,9 @@
在创世纪章节中我们简单介绍了Go语言的演化基因族谱对其中来自于贝尔实验室的特有并发编程基因做了重点介绍最后引出了Go语言版的“Hello, World”程序。其实“Hello, World”程序是展示各种语言特性的最好的例子是通向该语言的一个窗口。这一节我们将沿着各个编程语言演化的时间轴简单回顾下“Hello, World”程序是如何逐步演化到目前的Go语言形式、最终完成它的革命使命的。
![](../images/ch1.2-1-go-history.png)
![](../images/ch1-4-go-history.png)
*图 1.2-1 Go语言并发演化历史*
*图 1-4 Go语言并发演化历史*
## 1.2.1 B语言 - Ken Thompson, 1972
@ -102,9 +102,9 @@ print("Hello,", "World", "\n");
从上面的程序中,除了猜测`print`函数可以支持多个参数外我们很难看到Newsqueak语言相关的特性。由于Newsqueak语言和Go语言相关的特性主要是并发和管道。因此我们这里通过一个并发版本的“素数筛”算法来略窥Newsqueak语言的特性。“素数筛”的原理如图
![](../images/ch1.2-2-prime-sieve.png)
![](../images/ch1-5-prime-sieve.png)
*图 1.2-2 素数筛*
*图 1-5 素数筛*
Newsqueak语言并发版本的“素数筛”程序如下
@ -164,9 +164,9 @@ Newsqueak语言中并发体和管道的语法和Go语言已经比较接近了
由于Alef语言同时支持进程和线程并发体而且在并发体中可以再次启动更多的并发体导致了Alef的并发状态会异常复杂。同时Alef没有自动垃圾回收机制Alef因为保留的C语言灵活的指针特性也导致了自动垃圾回收机制实现比较困难各种资源充斥于不同的线程和进程之间导致并发体的内存资源管理异常复杂。Alef语言全部继承了C语言的语法可以认为是增强了并发语法的C语言。下图是Alef语言文档中展示的一个可能的并发体状态
![](../images/ch1.2-3-alef.png)
![](../images/ch1-6-alef.png)
*图 1.2-3 Alef并发模型*
*图 1-6 Alef并发模型*
Alef语言并发版本的“Hello World”程序如下

View File

@ -27,9 +27,9 @@ var d = [...]int{1, 2, 4: 5, 6} // 定义一个长度为6的int类型数组, 元
数组的内存结构比较简单。比如下面是一个`[4]int{2,3,5,7}`数组值对应的内存结构:
![](../images/ch1.3-1-array-4int.ditaa.png)
![](../images/ch1-7-array-4int.ditaa.png)
*图 1.3-1 数组布局*
*图 1-7 数组布局*
Go语言中数组是值语义。一个数组变量即表示整个数组它并不是隐式的指向第一个元素的指针比如C语言的数组而是一个完整的值。当一个数组变量被赋值或者被传递的时候实际上会复制整个数组。如果数组较大的话数组的赋值也会有较大的开销。为了避免复制数组带来的开销可以传递一个指向数组的指针但是数组指针并不是数组。
@ -161,9 +161,9 @@ type StringHeader struct {
我们可以看看字符串“Hello, world”本身对应的内存结构
![](../images/ch1.3-2-string-1.ditaa.png)
![](../images/ch1-8-string-1.ditaa.png)
*图 1.3-2 字符串布局*
*图 1-8 字符串布局*
分析可以发现“Hello, world”字符串底层数据和以下数组是完全一致的
@ -214,9 +214,9 @@ fmt.Println("\xe7\x95\x8c") // 打印: 界
下图展示了“Hello, 世界”字符串的内存结构布局:
![](../images/ch1.3-3-string-2.ditaa.png)
![](../images/ch1-9-string-2.ditaa.png)
*图 1.3-3 字符串布局*
*图 1-9 字符串布局*
Go语言的字符串中可以存放任意的二进制字节序列而且即使是UTF8字符序列也可能会遇到坏的编码。如果遇到一个错误的UTF8编码输入将生成一个特别的Unicode字符\uFFFD这个字符在不同的软件中的显示效果可能不太一样在印刷中这个符号通常是一个黑色六角形或钻石形状里面包含一个白色的问号<E58FB7>
@ -368,9 +368,9 @@ type SliceHeader struct {
可以看出切片的开头部分和Go字符串是一样的但是切片多了一个`Cap`成员表示切片指向的内存空间的最大容量(对应元素的个数,而不是字节数)。下图是`x := []int{2,3,5,7,11}``y := x[1:3]`两个切片对应的内存结构。
![](../images/ch1.3-4-slice-1.ditaa.png)
![](../images/ch1-10-slice-1.ditaa.png)
*图 1.3-4 切片布局*
*图 1-10 切片布局*
让我们看看切片有哪些定义方式:

View File

@ -4,9 +4,9 @@
Go语言程序的初始化和执行总是从`main.main`函数开始的。但是如果`main`包导入了其它的包,则会按照顺序将它们包含进`main`包里(这里的导入顺序依赖具体实现,一般可能是以文件名或包路径名的字符串顺序导入)。如果某个包被多次导入的话,在执行的时候只会导入一次。当一个包被导入时,如果它还导入了其它的包,则先将其它的包包含进来,然后创建和初始化这个包的常量和变量,再调用包里的`init`函数,如果一个包有多个`init`函数的话,调用顺序未定义(实现可能是以文件名的顺序调用),同一个文件内的多个`init`则是以出现的顺序依次调用(`init`不是普通函数,可以定义有多个,所以也不能被其它函数调用)。最后,当`main`包的所有包级常量、变量被创建和初始化完成,并且`init`函数被执行后,才会进入`main.main`函数程序开始正常执行。下图是Go程序函数启动顺序的示意图
![](../images/ch1.4-1-init.ditaa.png)
![](../images/ch1-11-init.ditaa.png)
*图 1.4-1 包初始化流程*
*图 1-11 包初始化流程*
要注意的是,在`main.main`函数执行之前所有代码都运行在同一个goroutine也就是程序的主系统线程中。因此如果某个`init`函数内部用go关键字启动了新的goroutine的话新的goroutine只有在进入`main.main`函数之后才可能被执行到。

View File

@ -259,9 +259,9 @@ func main() {
Go程序的初始化和执行总是从`main.main`函数开始的。但是如果`main`包里导入了其它的包,则会按照顺序将它们包含进`main`包里(这里的导入顺序依赖具体实现,一般可能是以文件名或包路径名的字符串顺序导入)。如果某个包被多次导入的话,在执行的时候只会导入一次。当一个包被导入时,如果它还导入了其它的包,则先将其它的包包含进来,然后创建和初始化这个包的常量和变量。然后就是调用包里的`init`函数,如果一个包有多个`init`函数的话,实现可能是以文件名的顺序调用,同一个文件内的多个`init`则是以出现的顺序依次调用(`init`不是普通函数,可以定义有多个,所以不能被其它函数调用)。最终,在`main`包的所有包常量、包变量被创建和初始化,并且`init`函数被执行后,才会进入`main.main`函数程序开始正常执行。下图是Go程序函数启动顺序的示意图
![](../images/ch1.5-1-init.ditaa.png)
![](../images/ch1-12-init.ditaa.png)
*图 1.5-1 包初始化流程*
*图 1-12 包初始化流程*
要注意的是,在`main.main`函数执行之前所有代码都运行在同一个Goroutine中也是运行在程序的主系统线程中。如果某个`init`函数内部用go关键字启动了新的Goroutine的话新的Goroutine和`main.main`函数是并发执行的。

View File

@ -416,9 +416,9 @@ func main() {
在“Hello world 的革命”一节中我们为了演示Newsqueak的并发特性文中给出了并发版本素数筛的实现。并发版本的素数筛是一个经典的并发例子通过它我们可以更深刻地理解Go语言的并发特性。“素数筛”的原理如图
![](../images/ch1.6-1-prime-sieve.png)
![](../images/ch1-13-prime-sieve.png)
*图 1.6-1 素数筛*
*图 1-13 素数筛*
我们需要先生成最初的`2, 3, 4, ...`自然数序列不包含开头的0、1

View File

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB