ch1: 统一图像文件名命名规则, 以章节为前缀名
@ -2,11 +2,11 @@
|
||||
|
||||
Go语言最初由Google公司的Robert Griesemer、Ken Thompson和Rob Pike三个大牛于2007年开始设计发明,设计新语言的最初的洪荒之力来自于对超级复杂的C++11特性的吹捧报告的鄙视,最终的目标是设计网络和多核时代的C语言。到2008年中期,语言的大部分特性设计已经完成,并开始着手实现编译器和运行时,大约在这一年Russ Cox作为主力开发者加入。到了2010年,Go语言已经逐步趋于稳定,并在9月正式发布Go语言并开源了代码。
|
||||
|
||||

|
||||

|
||||
|
||||
Go语言很多时候被描述为“类C语言”,或者是“21世纪的C语言”。从各种角度看,Go语言确实是从C语言继承了相似的表达式语法、控制流结构、基础数据类型、调用参数传值、指针等诸多编程思想,还有彻底继承和发扬了C语言简单直接的暴力编程哲学等。下面是《Go语言圣经》中给出的Go语言的基因图谱,我们可以从中看到有那些编程语言对Go语言产生了影响。
|
||||
|
||||

|
||||

|
||||
|
||||
首先看基因图谱的左边一支。可以明确看出Go语言的并发特性是由贝尔实验室的Hoare于1978年发布的CSP理论演化而来。其后,CSP并发模型在Squeak/NewSqueak和Alef等编程语言中逐步完善并走向实际应用,最终这些设计经验被消化并吸收到了Go语言中。业界比较熟悉的Erlang编程语言的并发编程模型也是CSP理论的另一种实现。
|
||||
|
||||
@ -24,13 +24,13 @@ CSP并发模型最经典的实际应用是来自爱立信发明的Erlang编程
|
||||
|
||||
可以从Go语言库早期代码库日志可以看出最直接的演化历程(Git用`git log --before={2008-03-03} --reverse`命令查看):
|
||||
|
||||

|
||||

|
||||
|
||||
从早期提交日志中也可以看出,Go语言是从Ken Thompson发明的B语言、Dennis M. Ritchie发明的C语言逐步演化过来的,它首先是C语言家族的成员,因此很多人将Go语言称为21世纪的C语言。
|
||||
|
||||
下面是Go语言中来自贝尔实验室特有并发编程基因的演化过程:
|
||||
|
||||

|
||||

|
||||
|
||||
纵观整个贝尔实验室的编程语言的发展进程,从B语言、C语言、Newsqueak、Alef、Limbo语言一路走来,Go语言继承了来着贝尔实验室的半个世纪的软件设计基因,终于完成了C语言革新的使命。纵观这几年来的发展趋势,Go语言已经成为云计算、云存储时代最重要的基础编程语言。
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
在创世纪章节中我们简单介绍了Go语言的演化基因族谱,对其中来自贝尔实验室特有并发编程基因做了重点介绍,最后引出了Go语言版的“Hello, World”程序。其实“Hello, World”程序是展示各种语言特性的最好的例子,是通向该语言的一个窗口。这一节我们就沿着各个编程语言演化的时间轴,简单回顾下“Hello, World”程序是如何逐步演化到目前的Go语言形式、最终完成“Hello, World”革命使命的。
|
||||
|
||||

|
||||

|
||||
|
||||
## B语言 - Ken Thompson, 1972
|
||||
|
||||
@ -88,7 +88,7 @@ print("Hello,", "World", "\n");
|
||||
|
||||
从上面的程序中,除了猜测`print`函数可以支持多个参数外,我们很难看到Newsqueak语言相关的特性。由于Newsqueak语言和Go语言相关的特性主要是并发和管道。因此,我们这里通过一个并发版本的“素数筛”算法来略窥Newsqueak语言的特性。“素数筛”的原理如图:
|
||||
|
||||

|
||||

|
||||
|
||||
Newsqueak语言并发版本的“素数筛”程序如下:
|
||||
|
||||
@ -146,7 +146,7 @@ Newsqueak语言中并发体和管道的语法和Go语言已经比较接近了,
|
||||
|
||||
由于Alef语言同时支持进程和线程并发体,而且在并发体中可以再次启动更多的并发体,导致了Alef的并发状态会异常复杂。同时Alef没有自动垃圾回收机制(Alef因为保留的C语言灵活的指针特性,也导致了自动垃圾回收机制实现比较困难),各种资源充斥于不同的线程和进程之间,导致并发体的内存资源管理异常复杂。Alef语言全部继承了C语言的语法,可以认为是增强了并发语法的C语言。下图是Alef语言文档中展示的一个可能的并发体状态:
|
||||
|
||||

|
||||

|
||||
|
||||
Alef语言并发版本的“Hello World”程序如下:
|
||||
|
||||
|
@ -27,7 +27,7 @@ var d = [...]int{1, 2, 4: 5, 6} // 定义一个长度为6的int类型数组, 元
|
||||
|
||||
数组的内存结构比较简单。比如下面是一个`[4]int{2,3,5,7}`数组值对应的内存结构:
|
||||
|
||||

|
||||

|
||||
|
||||
Go语言中数组是值语义。一个数组变量即表示整个数组,它并不是隐式的指向第一个元素的指针(比如C语言的数组),而是一个完整的值。当一个数组变量被赋值或者被传递的时候,实际上会复制整个数组。如果数组较大的话,数组的赋值也会有较大的开销。为了避免复制数组带来的开销,可以传递一个指向数组的指针,但是数组指针并不是数组。
|
||||
|
||||
@ -158,7 +158,7 @@ type StringHeader struct {
|
||||
|
||||
我们可以看看字符串“Hello, world”本身对应的内存结构:
|
||||
|
||||

|
||||

|
||||
|
||||
分析可以发现,“Hello, world”字符串底层数据和以下数组是完全一致的:
|
||||
|
||||
@ -208,7 +208,7 @@ fmt.Println("\xe7\x95\x8c") // 打印: 界
|
||||
|
||||
下图展示了“Hello, 世界”字符串的内存结构布局:
|
||||
|
||||

|
||||

|
||||
|
||||
Go语言的字符串中可以存放任意的二进制字节序列,而且即是是UTF8字符序列也可能会遇到坏的编码。如果遇到一个错误的UTF8编码输入,将生成一个特别的UNICODE字符‘\uFFFD’,这个字符在不同的软件中的显示效果可能不太一样,在印刷中这个符号通常是一个黑色六角形或钻石形状,里面包含一个白色的问号‘<E58FB7>’。
|
||||
|
||||
@ -359,7 +359,7 @@ type SliceHeader struct {
|
||||
|
||||
可以看出切片的开头部分和Go字符串是一样的,但是切片多了一个`Cap`成员表示切片指向的内存空间的最大容量(对应元素的个数,而不是字节数)。下图是`x := []int{2,3,5,7,11}`和`y := x[1:3]`两个切片对应的内存结构。
|
||||
|
||||

|
||||

|
||||
|
||||
让我们看看切片有哪些定义方式:
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
Go语言程序的初始化和执行总是从`main.main`函数开始的。但是如果`main`包里导入了其它的包,则会按照顺序将它们包含进`main`包里(这里的导入顺序依赖具体实现,一般可能是以文件名或包路径名的字符串顺序导入)。如果某个包被多次导入的话,在执行的时候只会导入一次。当一个包被导入时,如果它还导入了其它的包,则先将其它的包包含进来,然后创建和初始化这个包的常量和变量。然后就是调用包里的`init`函数,如果一个包有多个`init`函数的话,实现可能是以文件名的顺序调用,同一个文件内的多个`init`则是以出现的顺序依次调用(`init`不是普通函数,可以定义有多个,所有也不能被其它函数调用)。最后,当`main`包的所有包常量、包变量被创建和初始化,并且`init`函数被执行后,才会进入`main.main`函数,程序开始正常执行。下图是Go程序函数启动顺序的示意图:
|
||||
|
||||

|
||||

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

|
||||

|
||||
|
||||
要注意的是,在`main.main`函数执行之前所有代码都运行在同一个goroutine中,也是运行在程序的主系统线程中。如果某个`init`函数内部用go关键字启动了新的goroutine的话,新的goroutine只有在进入`main.main`函数之后才可能被执行到。
|
||||
|
||||
|
@ -450,7 +450,7 @@ func New(fs vfs.FileSystem, gate chan bool) *gatefs {
|
||||
|
||||
在“Hello world 的革命”一节中,我们为了演示Newsqueak的并发特性,文中给出了并发版本素数筛的实现。并发版本的素数筛是一个经典的并发例子,通过它我们可以更深刻地理解Go语言的并发特性。“素数筛”的原理如图:
|
||||
|
||||

|
||||

|
||||
|
||||
我们需要先生成最初的`2, 3, 4, ...`自然数序列(不包含开头的0、1):
|
||||
|
||||
|
@ -14,17 +14,17 @@ Notepad++是Windows操作系统下严肃程序员们编写代码的利器!Note
|
||||
|
||||
下面是Go语言的语法高亮预览,其中右侧是Go函数列表:
|
||||
|
||||

|
||||

|
||||
|
||||
下面是Go语言汇编的语法高亮预览:其中右侧是汇编函数列表:
|
||||
|
||||

|
||||

|
||||
|
||||
对于Protobuf或GRPC的用户,可以从 https://github.com/chai2010/notepadplus-protobuf 下载相应的插件。
|
||||
|
||||
下面是Protobuf的语法高亮预览:
|
||||
|
||||

|
||||

|
||||
|
||||
**配置Notepad++的语法高亮**
|
||||
|
||||
@ -49,7 +49,7 @@ Notepad++还支持关键字的自动补全。假设Notepad++安装在`<DIR>`目
|
||||
|
||||
下面是内置函数`println`自动补全后函数参数提示的预览图:
|
||||
|
||||

|
||||

|
||||
|
||||
这是一个比较鸡肋的功能,用户根据自己需要选择是否安装。
|
||||
|
||||
@ -59,7 +59,7 @@ Notepad++还支持关键字的自动补全。假设Notepad++安装在`<DIR>`目
|
||||
|
||||
不过Windows自带的命令行工具比较简陋,不是理想的命令行开发环境。如果读者还没有自己合适命令行环境,可以试试ConEmu这个免费命令行软件。ConEmu支持多标签页窗口,复制粘贴也比较方便。下面是ConEmu的预览图:
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
ConEmu的主页在:http://conemu.github.io/ 。
|
||||
@ -68,7 +68,7 @@ ConEmu的主页在:http://conemu.github.io/ 。
|
||||
|
||||
对于macOS平台的用户,免费的轻量级软件推荐TextMate编辑器。TextMate是macOS下的Notepadd++工具。支持目录列表,支持Go语言的诸多特性。下面是TextMate的预览图:
|
||||
|
||||

|
||||

|
||||
|
||||
对于iPad Pro用户,目前也有不少编辑软件对Go语言提供了不错的支持。比如Textastic Code、Coda等,很多都支持iPad和macOS平台的同步,它们一般都是需要单独购买的收费软件。
|
||||
|
||||
@ -86,7 +86,7 @@ Textastic是一款收费应用,它是macOS/iOS下著名的轻量级代码编
|
||||
|
||||
在macOS下,Textastic的界面和TextMate非常相似。不过Textastic在左边侧栏提供了基于工程的检索工具。下面是macOS下Textastic的预览图:
|
||||
|
||||

|
||||

|
||||
|
||||
因为iOS环境不支持编译和调试,如果需要在iOS环境编写Go程序,首先要解决和其他平台的共享问题。这样可以在iOS环境编写代码,然后在其他电脑上进行编译和测试。
|
||||
|
||||
@ -94,13 +94,13 @@ Textastic是一款收费应用,它是macOS/iOS下著名的轻量级代码编
|
||||
|
||||
下面是iPad Pro下Textastic的预览图:
|
||||
|
||||

|
||||

|
||||
|
||||
如果Go语言代码是放在Git服务器中,可以通过Working Copy应用将仓库克隆到iOS中,然后再Textastic中通过iOS协议打开工作区文件。编辑完成之后,在通过Working Copy将修改提交到中心仓库中。
|
||||
|
||||
下面是iPad Pro下Working Copy查看Git更新日志的预览图:
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
## 跨平台编辑器: Github Atom
|
||||
@ -109,7 +109,7 @@ Gtihub Atom是Github专门为程序员推出的一个跨平台文本编辑器。
|
||||
|
||||
Github Atom的预览图:
|
||||
|
||||

|
||||

|
||||
|
||||
Github Atom作为一个Go语言编辑器,不足之处是没有Go汇编语言的高亮显示插件。而且Github Atom对于大文件的支持性能不是很好。
|
||||
|
||||
@ -121,11 +121,11 @@ VSCode虽然是基于Gtihub Atom而来,不过VSCode支持Go语言的代码自
|
||||
|
||||
下面是用VScode打开的Go语言工程的预览图:
|
||||
|
||||

|
||||

|
||||
|
||||
因为,VSCode和Gtihub Atom都是采用的Chrome核心,它不仅仅能编辑显示代码,还可以用来显示网页查看图像,甚至可以在一个分屏窗口中播放视频文件:
|
||||
|
||||

|
||||

|
||||
|
||||
VSCode安装Go语言插件中,默认的很多参数设置比较严格。比如,默认会使用`golint`来严格检查代码是否符合编码规范,对于git工程启动时还会自动获取和刷新。对于一般的Go语言代码来说,`golint`检测过于严格,很难完全通过(Go语言标准库也无法完全通过),从而导致每次保存时都会提示很多干扰信息。当然,对相对稳定的程序定期做`golint`检查也是有必要,它的信息可以作为我们改进代码的参考。同样的,如果git仓库有密码认证的话,VSCode在启动的时候总是弹出输入密码的对话框。
|
||||
|
||||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.7 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |