├── .gitignore ├── LICENSE ├── README.md ├── SUMMARY.md ├── TOC.md ├── config.json ├── cover └── cover.jpeg ├── eBook ├── chapter0 │ ├── 00.1.md │ ├── 00.3.md │ ├── 00.4.1.md │ └── 00.4.md ├── chapter1 │ ├── 01.1.md │ ├── 01.2.md │ ├── 01.3.md │ ├── 01.4.1.md │ └── 01.4.md ├── chapter10 │ ├── 10.0.md │ ├── 10.1.1.md │ ├── 10.1.md │ ├── 10.10.md │ ├── 10.2.md │ ├── 10.3.1.md │ ├── 10.3.2.md │ ├── 10.3.md │ ├── 10.4.1.md │ ├── 10.4.2.md │ ├── 10.4.3.md │ ├── 10.4.4.md │ ├── 10.4.5.md │ ├── 10.4.md │ ├── 10.5.1.1.md │ ├── 10.5.1.md │ ├── 10.5.2.md │ ├── 10.5.3.md │ ├── 10.5.md │ ├── 10.6.md │ ├── 10.7.1.md │ ├── 10.7.2.md │ ├── 10.7.md │ ├── 10.8.md │ └── 10.9.md ├── chapter11 │ ├── 11.0.md │ ├── 11.1.1.md │ ├── 11.1.md │ ├── 11.10.md │ ├── 11.11.md │ ├── 11.12.md │ ├── 11.13.md │ ├── 11.14.md │ ├── 11.15.md │ ├── 11.16.md │ ├── 11.2.md │ ├── 11.3.md │ ├── 11.4.md │ ├── 11.5.1.md │ ├── 11.5.2.md │ ├── 11.5.3.md │ ├── 11.5.4.1.md │ ├── 11.5.4.2.md │ ├── 11.5.4.md │ ├── 11.5.md │ ├── 11.6.md │ ├── 11.7.1.md │ ├── 11.7.md │ ├── 11.8.1.md │ ├── 11.8.2.md │ ├── 11.8.md │ └── 11.9.md ├── chapter12 │ ├── 12.0.md │ ├── 12.1.1.md │ ├── 12.1.2.md │ ├── 12.1.3.md │ ├── 12.1.md │ ├── 12.10.1.md │ ├── 12.10.2.md │ ├── 12.10.3.md │ ├── 12.10.md │ ├── 12.11.md │ ├── 12.12.md │ ├── 12.13.md │ ├── 12.14.md │ ├── 12.2.md │ ├── 12.3.md │ ├── 12.4.md │ ├── 12.5.md │ ├── 12.6.1.md │ ├── 12.6.2.md │ ├── 12.6.md │ ├── 12.7.1.md │ ├── 12.7.2.md │ ├── 12.7.md │ ├── 12.8.1.md │ ├── 12.8.md │ ├── 12.9.1.md │ └── 12.9.md ├── chapter13 │ ├── 13.0.md │ ├── 13.1.md │ ├── 13.10.md │ ├── 13.11.md │ ├── 13.12.md │ ├── 13.2.1.md │ ├── 13.2.md │ ├── 13.3.1.md │ ├── 13.3.md │ ├── 13.4.md │ ├── 13.5.md │ ├── 13.6.1.md │ ├── 13.6.md │ ├── 13.7.1.md │ ├── 13.7.2.md │ ├── 13.7.md │ ├── 13.8.1.md │ ├── 13.8.md │ └── 13.9.md ├── chapter2 │ ├── 02.1.md │ ├── 02.2.md │ ├── 02.3.1.md │ ├── 02.3.2.md │ ├── 02.3.3.md │ ├── 02.3.4.md │ ├── 02.3.5.md │ ├── 02.3.md │ ├── 02.5.1.md │ ├── 02.5.2.md │ ├── 02.5.md │ ├── 02.6.md │ └── 02.7.md ├── chapter3 │ ├── 03.1.1.md │ ├── 03.1.2.md │ ├── 03.1.3.md │ ├── 03.1.4.md │ ├── 03.1.md │ ├── 03.10.md │ ├── 03.3.1.md │ ├── 03.3.2.md │ ├── 03.3.3.md │ ├── 03.3.4.md │ ├── 03.3.5.md │ ├── 03.3.6.md │ ├── 03.3.7.md │ ├── 03.3.md │ ├── 03.4.0.md │ ├── 03.4.1.md │ ├── 03.4.2.md │ ├── 03.5.1.md │ ├── 03.5.md │ ├── 03.6.md │ ├── 03.7.1.md │ ├── 03.7.2.md │ ├── 03.7.3.md │ ├── 03.7.4.md │ ├── 03.7.5.md │ ├── 03.7.md │ ├── 03.8.md │ └── 03.9.md ├── chapter4 │ ├── 04.0.md │ ├── 04.1.md │ ├── 04.10.md │ ├── 04.11.md │ ├── 04.2.1.md │ ├── 04.2.2.md │ ├── 04.2.md │ ├── 04.3.md │ ├── 04.4.1.md │ ├── 04.4.2.md │ ├── 04.4.3.md │ ├── 04.4.4.md │ ├── 04.4.md │ ├── 04.5.1.md │ ├── 04.5.2.md │ ├── 04.5.3.md │ ├── 04.5.md │ ├── 04.6.md │ ├── 04.7.md │ ├── 04.8.md │ └── 04.9.md ├── chapter5 │ ├── 05.0.md │ ├── 05.1.md │ ├── 05.10.1.md │ ├── 05.10.md │ ├── 05.11.md │ ├── 05.12.md │ ├── 05.13.md │ ├── 05.2.md │ ├── 05.3.1.md │ ├── 05.3.2.md │ ├── 05.3.md │ ├── 05.4.1.md │ ├── 05.4.2.md │ ├── 05.4.3.md │ ├── 05.4.md │ ├── 05.5.1.md │ ├── 05.5.2.md │ ├── 05.5.md │ ├── 05.6.1.md │ ├── 05.6.2.md │ ├── 05.6.md │ ├── 05.7.1.md │ ├── 05.7.md │ ├── 05.8.1.md │ ├── 05.8.md │ ├── 05.9.1.md │ ├── 05.9.2.md │ ├── 05.9.3.md │ └── 05.9.md ├── chapter6 │ ├── 06.0.md │ ├── 06.1.md │ ├── 06.2.1.md │ ├── 06.2.2.md │ ├── 06.2.3.md │ ├── 06.2.4.md │ ├── 06.2.5.md │ ├── 06.2.6.md │ ├── 06.2.7.md │ ├── 06.2.md │ └── 06.3.md ├── chapter7 │ ├── 07.0.md │ ├── 07.1.md │ ├── 07.2.md │ ├── 07.3.md │ ├── 07.4.1.md │ ├── 07.4.2.md │ ├── 07.4.md │ ├── 07.5.1.md │ ├── 07.5.2.md │ ├── 07.5.3.md │ ├── 07.5.md │ ├── 07.6.md │ ├── 07.7.md │ ├── 07.8.md │ └── 07.9.md ├── chapter8 │ ├── 08.0.md │ ├── 08.1.md │ ├── 08.10.md │ ├── 08.11.md │ ├── 08.12.md │ ├── 08.13.md │ ├── 08.14.1.md │ ├── 08.14.2.md │ ├── 08.14.md │ ├── 08.15.1.md │ ├── 08.15.md │ ├── 08.16.md │ ├── 08.17.md │ ├── 08.18.md │ ├── 08.19.md │ ├── 08.2.md │ ├── 08.20.md │ ├── 08.21.md │ ├── 08.22.md │ ├── 08.23.md │ ├── 08.3.1.md │ ├── 08.3.md │ ├── 08.4.md │ ├── 08.5.1.md │ ├── 08.5.2.md │ ├── 08.5.3.md │ ├── 08.5.4.md │ ├── 08.5.md │ ├── 08.6.md │ ├── 08.7.md │ ├── 08.8.md │ ├── 08.9.md │ └── 8.2.md ├── chapter9 │ ├── 09.0.md │ ├── 09.1.1.md │ ├── 09.1.2.md │ ├── 09.1.md │ ├── 09.2.1.md │ ├── 09.2.2.md │ ├── 09.2.md │ ├── 09.3.1.md │ ├── 09.3.md │ ├── 09.4.1.md │ ├── 09.4.2.md │ ├── 09.4.3.md │ ├── 09.4.md │ ├── 09.5.md │ ├── 09.6.md │ ├── 09.7.md │ └── 09.8.md └── examples │ ├── chapter10 │ ├── bufChannel.go │ ├── chSquare.go │ ├── closeNilChannel.go │ ├── defineOrder.go │ ├── forgetMutex.go │ ├── maxprocs.go │ ├── monitor.go │ ├── mutex.go │ ├── nilChannel.go │ ├── noRaceC.go │ ├── raceC.go │ ├── rwMutex.go │ ├── select.go │ ├── simpleContext.go │ ├── slowWWW.go │ ├── timeOut1.go │ ├── timeOut2.go │ ├── useContext.go │ └── workerPool.go │ ├── chapter11 │ ├── benchmarkMe.go │ ├── benchmarkMe_test.go │ ├── betterProfile.go │ ├── cannotReach.go │ ├── documentMe.go │ ├── documentMe_test.go │ ├── ex.go │ ├── ex_test.go │ ├── goGC.go │ ├── profileMe.go │ ├── testMe.go │ ├── testMe_test.go │ ├── writingBU.go │ ├── writingBU_test.go │ └── xCompile.go │ ├── chapter12 │ ├── NSrecords.go │ ├── DNS.go │ ├── MXrecords.go │ ├── advancedWebClient.go │ ├── anotherTimeOut.go │ ├── clientTimeOut.go │ ├── home.gohtml │ ├── httpTrace.go │ ├── insert.gohtml │ ├── kvWeb.go │ ├── netCapabilities.go │ ├── netConfig.go │ ├── serverTimeOut.go │ ├── testWWW.go │ ├── testWWW_test.go │ ├── update.gohtml │ ├── webClient.go │ ├── www.go │ └── wwwProfile.go │ ├── chapter13 │ ├── RPCclient.go │ ├── RPCserver.go │ ├── TCPclient.go │ ├── TCPserver.go │ ├── UDPserver.go │ ├── fiboTCP.go │ ├── kvTCP.go │ ├── lowLevel.go │ ├── otherTCPclient.go │ ├── sharedRPC.go │ └── syscallNet.go │ ├── chapter3 │ ├── constants.go │ ├── copySlice.go │ ├── failMap.go │ ├── lenCap.go │ ├── parseDate.go │ ├── parseTime.go │ ├── pointers.go │ ├── slices.go │ ├── sortSlice.go │ ├── timeDate.go │ ├── usingMaps.go │ └── usingTime.go │ ├── chapter4 │ ├── calculatePi.go │ ├── chargeDT.go │ ├── findIPv4.go │ ├── keyValue.go │ ├── pointerStruct.go │ ├── runes.go │ ├── selectColumn.go │ ├── strings.go │ ├── structures.go │ ├── switch.go │ ├── tuples.go │ ├── unicode.go │ └── useStrings.go │ ├── chapter5 │ ├── binTree.go │ ├── conHeap.go │ ├── conList.go │ ├── conRing.go │ ├── doublyLList.go │ ├── generatePassword.go │ ├── hashTable.go │ ├── hashTableLookup.go │ ├── linkedList.go │ ├── queue.go │ ├── randomNumbers.go │ └── stack.go │ ├── chapter6 │ ├── aPackage.go │ ├── funFun.go │ ├── functions.go │ ├── ptrFun.go │ ├── returnFunction.go │ ├── returnNames.go │ ├── returnPtr.go │ └── useAPackage.go │ ├── chapter7 │ ├── advRefl.go │ ├── assertion.go │ ├── goCoIn.go │ ├── methods.go │ ├── myInterface.go │ ├── ooo.go │ ├── reflection.go │ ├── switch.go │ └── useInterface.go │ ├── chapter8 │ ├── funWithFlag.go │ └── simpleFlag.go │ └── chapter9 │ ├── create.go │ ├── pipeline.go │ ├── readCh.go │ ├── simple.go │ ├── syncGo.go │ └── writeCh.go └── images ├── chapter10 ├── 10.1-1.jpg ├── 10.4.5.jpg ├── 10.5.1-1.jpg ├── 10.5.1-2.jpg ├── 10.5.1-3.jpg ├── 10.6-1.jpg ├── 10.6-2.jpg └── 10.7.1.jpg ├── chapter11 ├── 11.13-1.jpg ├── 11.13-2.jpg ├── 11.13-3.jpg ├── 11.13-4.jpg ├── 11.2.jpg ├── 11.5.2-1.jpg ├── 11.5.2-2.1.jpg ├── 11.5.2-2.2.jpg ├── 11.5.2-3.jpg ├── 11.5.2-4.jpg ├── 11.5.2-5.jpg ├── 11.5.2-6.jpg ├── 11.5.3-1.jpg ├── 11.5.3-2.jpg ├── 11.5.4.1-1.jpg ├── 11.5.4.1-2.jpg ├── 11.5.4.2-1.jpg ├── 11.5.4.2-2.jpg ├── 11.6-1.jpg ├── 11.6-2.jpg ├── 11.6-3.jpg ├── 11.7.1-1.jpg ├── 11.7.1-2.jpg ├── 11.7.1-3.jpg ├── 11.8.1-1.jpg ├── 11.8.1-2.jpg ├── 11.9-1.jpg └── 11.9-2.jpg ├── chapter12 ├── 12.7.1-1.jpg ├── 12.7.1-2.jpg ├── 12.7.2-1.jpg ├── 12.7.2-2.jpg ├── 12.7.2-3.jpg ├── 12.7.2-4.jpg └── 12.9.jpg ├── chapter2 └── 02.3-1.jpg ├── chapter5 ├── 05.3-1.jpg ├── 05.4-1.jpg ├── 05.5-1.jpg ├── 05.5-2.jpg ├── 05.6-1.jpg └── 05.6-2.jpg ├── chapter8 ├── 08.2.jpg └── 08.8.png └── cover.jpeg /.gitignore: -------------------------------------------------------------------------------- 1 | *.*~ 2 | *.*~.* 3 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 4 | *.o 5 | *.a 6 | *.so 7 | 8 | # Folders 9 | _obj 10 | _test 11 | .idea 12 | 13 | # Architecture specific extensions/prefixes 14 | *.[568vq] 15 | [568vq].out 16 | 17 | *.cgo1.go 18 | *.cgo2.c 19 | _cgo_defun.c 20 | _cgo_gotypes.go 21 | _cgo_export.* 22 | 23 | _testmain.go 24 | 25 | *.exe 26 | .DS_Store 27 | the-way-to-go.sublime-project 28 | the-way-to-go.sublime-workspace 29 | 30 | *.pdf 31 | 32 | *.html 33 | *.htm 34 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "玩转 Go", 3 | "introduction": "Go 进阶书籍《Mastering Go》的中文译本。", 4 | "path": { 5 | "content": "eBook", 6 | "readme": "README.md" 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /cover/cover.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/cover/cover.jpeg -------------------------------------------------------------------------------- /eBook/chapter0/00.1.md: -------------------------------------------------------------------------------- 1 | # **前言** 2 | 3 | ​ 这本书能够帮助你成为一个更棒的Go开发者。 4 | 5 | ​ 我尽最大努力将这本书理论与实战兼顾,但是只有你的反馈才是评价这本书成功与否的标准。另外,本书的代码示例都是独立的,意味着你可以单独使用或者以其为模板创建更加复杂的应用。 6 | 7 | ​ 每章最后的练习题要亲自动手去敲,有什么问题尽管联系我,因为你的反馈与建议可以让本书的下一版本更加完善! 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /eBook/chapter0/00.4.1.md: -------------------------------------------------------------------------------- 1 | # **代码规范约定** 2 | 3 | 下面是关于本书的代码规范约定。 4 | 5 | 文本框中的内容:代码,数据库表名,文件夹名,文件名,扩展名,路径名,URL,用户输入等。 6 | 7 | 下面是代码块示例: 8 | 9 | ```go 10 | package main 11 | import ( 12 | "fmt" 13 | ) 14 | func main() { 15 | fmt.Println("This is a sample Go program!") 16 | } 17 | ``` 18 | 19 | 代码块中强调的代码,会用下划线或者加粗的形式给出: 20 | 21 | >import ( 22 | >"fmt" 23 | >) 24 | >func main() { 25 | > 26 | >**fmt.Println("This is a sample Go program!")** 27 | 28 | >} 29 | > 30 | > 31 | 32 | 命令行输入输出的格式如下所示: 33 | 34 | > $ date 35 | > 36 | > Sat Oct 21 20:09:20 EEST 2017 37 | > 38 | > $ go version 39 | > 40 | > go version go1.9.1 darwin/amd64 41 | > 42 | > 43 | 44 | **粗体**:意味着这是重要的内容,或者是从屏幕中输出的内容。 45 | -------------------------------------------------------------------------------- /eBook/chapter0/00.4.md: -------------------------------------------------------------------------------- 1 | # **更多信息** 2 | 3 | 为了更好地学习这本书,你需要拥有一台类UNIX系统的机器,Mac OS和Linux均可,并且安装较新版本的Go。本书大部分的代码可以在Microsoft windows机器上运行。 4 | 5 | 你应当尽可能地在你的程序中用上本书的知识,以验证哪些可以正常运行哪些不能。就像我之前说的那样,你应当亲自动手解决每章最后的练习题,或者编写自己的程序。 -------------------------------------------------------------------------------- /eBook/chapter1/01.1.md: -------------------------------------------------------------------------------- 1 | # **本书结构** 2 | 《Mastering Go》此本书可以从逻辑上分为三部分。第一部分由前四章构成,会快速的浏览一下Go语言的重要概念,包括用户输入输出、下载与使用第三方Go的包、如何编译Go的代码、如何在Go代码中调用C的代码,以及如何操作与使用Go的基本类型与组合类型等。 3 |
4 |
5 | 第二部分包括三个章节,主要介绍Go的代码如何组织、Go项目如何设计,以及Go语言的高级特性。 6 |
7 |
8 | 第三部分包括六个章节,主要涵盖Go语言实践过程中的高级话题,包括Go语言的系统编程、Go语言的并发,代码测试、优化与审计。本书最后两章会涉及网络编程的相关的概念。 9 |
10 |
11 | 本书展示的示例代码较少,主要有两个方面的原因:一方面,在了解一项技术实现的时候,不会被无止境的代码绕晕;另一方面,示例代码只是起到抛砖引玉的作用,你可以将它作为一个简单的开始,来编写你自己的应用。 12 |
13 |
14 | 本书主要以类Unix操作系统为例,但是并不代表Go的代码不能在Windows的操作系统中运行,因为Go的代码是可移植的!之所以这样介绍,是因为本书的示例代码在类Unix操作系统中,特别是Mac OS(版本为High Sierra)与Debian Linux系统中测试通过而已。 15 | 16 | -------------------------------------------------------------------------------- /eBook/chapter1/01.2.md: -------------------------------------------------------------------------------- 1 | # **Go的历史** 2 | Go是当下比较流行的开源的语言之一,第一次发布是在2009年年底。它开始于Google内部的项目,并且吸收了C、Pascal和Alef等语言的优质特性,最早由Robert Griesemer、Ken Thomson和Rob Pike联合撰写。三位作者的初衷是基于Go,能够开发一个可靠的和高效的软件系统。除了语法和标准函数之外,Go还提供了相当丰富的标准库的实现。 3 |
4 |
5 | 编写此书的时候,Go的稳定版本是1.9.1,1.9.2版本也即将发布: 6 |
7 | ``` 8 | $ date 9 | Sat Oct 21 20:09:20 EEST 2017 10 | $ go version 11 | go version go1.9.1 darwin/amd64 12 | ``` 13 |
14 |
15 | 我非常确信在本书真正出版的时候,通过命令go version命令,输出的结果跟上面一定不一样!但是,本书介绍的内容至少在若干年内不会过时,即使Go版本迭代如此之迅速。 16 |
17 |
18 | 如果你是第一次安装Go,你可以访问 [Golang学习](https://golang.org/dl/)。 还有一个很简单的办法,在类Unix系统中,已经可以通过包管理器安装Go编程语言包,你唯一要做的就是选择你喜欢的包管理器。 19 | 20 | -------------------------------------------------------------------------------- /eBook/chapter1/01.3.md: -------------------------------------------------------------------------------- 1 | # **为什么要学习Go** 2 | Go是当下比较热门和流行的语言,可以帮助你编写更加安全的代码、更少的bug。当然,有一些bug是非常难发现的!通常,Go语言希望成就更多、更快乐的编程者,因此Go的代码通俗易懂、很有吸引力,而且容易编写。 3 |
4 |
5 | 下一部分,我们会谈论Go的很多优秀的特点。 6 | -------------------------------------------------------------------------------- /eBook/chapter1/01.4.1.md: -------------------------------------------------------------------------------- 1 | # **Go是完美的么** 2 | 没有任何语言是完美的,Go也不例外。但是有些语言在某些方面具有特定的优势。就个人而言,我不喜欢Java,过去习惯于使用C++,但是现在一点也不喜欢它了。其中的原因是,我发现Java代码和C++代码不是很让人舒适。 3 |
4 |
5 | 当然,Go也是有缺点的: 6 | + Go不直接支持面向对象编程,这就使得那些已经习惯于面向对象编程的开发者来说非常痛苦。然而,你可以用组合的方式去模拟面向对象的实现方式。 7 | + 对于一些开发者来说,仍然偏爱C,Go不会完全取代C! 8 | + C仍然是处理最快的系统语言,因为类Unix系统就是用C开发的。 9 |
10 |
11 | 然而,这并不阻碍Go变得越来越流行! -------------------------------------------------------------------------------- /eBook/chapter1/01.4.md: -------------------------------------------------------------------------------- 1 | # **Go的优点** 2 | Go语言具有很多优点——其中一些是Go所特有的,有一些是与其他优秀的语言所共有的。 3 |
4 |
5 | Go最具优势的特性如下: 6 | + Go是由很多丰富经验的开发者所开发; 7 | + Go最早用于Google内部开发生产系统所使用; 8 | + Go的代码容易编写、易于阅读; 9 | + Go希望带给开发者快乐,快乐的心情容易编写优美的代码; 10 | + Go编译器会打印警告和错误信息,能够帮助开发者快速解决问题; 11 | + Go代码是可以移植的,特别是类Unix系统之间; 12 | + Go已经支持面向过程、并发和分布式编程; 13 | + Go支持垃圾回收机制,所以开发者无需关心内存分配与释放的问题; 14 | + Go没有预处理器,所以编译速度很快。因此,可以作为脚本语言使用; 15 | + Go可以构建Web应用,提供简单的Web服务器,供测试使用; 16 | + Go提供很多标准的库和包,简化开发者的开发工作。这些标准库和包经过大量的测试,可以安全使用; 17 | + Go默认启用静态链接,二进制文件很容易在同种操作系统间移植。一旦Go代码编译后,无需关心它所依赖的其他库,就可以很方便的在其他地方执行该二进制文件; 18 | + Go提供命令行式编译命令,无需GUI操作,深受Unix开发者的青睐; 19 | + Go支持Unicode编码,意味着不需要编写很多代码适配多种语言; 20 | + go的多个特性之间都是正交的,保证语言的稳定性和简单性。 21 | -------------------------------------------------------------------------------- /eBook/chapter10/10.0.md: -------------------------------------------------------------------------------- 1 | # **Go 并发-进阶讨论** 2 | 3 | 上一章介绍了 goroutines——Go 中最重要的特性,channels 和 pipelines。这章在讨论共享变量,`sync.Mutex` 和 `sync.RWMutex` 类型前,将继续从上章留下的这点出发来了解更多关于 goroutines,channels 和 `select` 关键字。这章也包括一些代码示例用于说明信号 channels,缓冲 channels,空 channels 和 channels 的 channels 的使用。另外,这章的前期您将了解俩个技巧用于一个 goroutine 在给定时间后的超时处理,因为没人能保证所有的 goroutines 能在期望的时间前都完成。这章将以检查竞争条件,`context` 标准包和工作池来结束。 4 | 5 | 在*玩转 Go* 的本章中,您将了解到如下主题: 6 | 7 | + `select` 关键字 8 | + Go 调度器如何工作 9 | + 俩个技巧用于一个完成时长超过预期的 goroutine 的超时处理 10 | + 信号 channels 11 | + 缓冲 channels 12 | + 空 channels 13 | + 监控 goroutines 14 | + channels 的 channels 15 | + 共享内存和互斥器 16 | + `sync.Mutex` 和 `sync.RWMutex` 类型 17 | + `contenxt` 包和它的功能 18 | + 工作池 19 | + 探测竞争条件 -------------------------------------------------------------------------------- /eBook/chapter10/10.1.1.md: -------------------------------------------------------------------------------- 1 | # **环境变量 GOMAXPROCS** 2 | 3 | 这个 `GOMAXPROCS` 环境变量(和Go 函数)允许您限制操作系统线程数,它能同时执行用户级 Go 代码。Go 1.5 版本开始,`GOMAXPROCS` 的默认值应该是您 Unix 机器的内核数。 4 | 5 | 如果您决定分配给 `GOMAXPROCS` 的值小于您的 Unix 机器的内核数的话,可能会影响您的程序的性能。然而,使用比可用内核大的 `GOMAXPROCS` 值也一定不会使您的程序运行的快。 6 | 7 | 您可用通过编程的方式来发现 `GOMAXPROCS` 环境变量的值,即相关代码。在下面的 `maxprocs.go` 程序中找到: 8 | 9 | ```go 10 | package main 11 | 12 | import ( 13 | "fmt" 14 | "runtime" 15 | ) 16 | 17 | func getGOMAXPROCS() int { 18 | return runtime.GOMAXPROCS(0) 19 | } 20 | 21 | func main() { 22 | fmt.Printf("GOMAXPROCS:%d\n", getGOMAXPROCS()) 23 | } 24 | ``` 25 | 26 | 在一台 Intel i7 处理器的机器上执行 `maxprocs.go` 产生如下输出: 27 | 28 | ```shell 29 | $go run maxprocs.go 30 | GOMAXPROCS: 8 31 | ``` 32 | 33 | 然而,您可以在程序执行前,通过改变 `GOMAXPROCS` 环境变量的值来修改上面的输出。在 `bash(1)` Unix shell 里执行下面的命令: 34 | 35 | ```shell 36 | $go version 37 | go version go1.9.4 darwin/amd64 38 | $export GOMAXPROCS=800; go run maxprocs.go 39 | GOMAXPROCS: 800 40 | $export GOMAXPROCS=4; go run maxprocs.go 41 | GOMAXPROCS: 4 42 | ``` -------------------------------------------------------------------------------- /eBook/chapter10/10.10.md: -------------------------------------------------------------------------------- 1 | # 本章小结 2 | 3 | 这章解决了许多关于 goroutine 的重要主题。然而,主要的是阐明 `select` 语句的作用。另外是说明 `context` 标准包的使用。 4 | 5 | 由于 `select` 语句的功能,通道是非常好的 Go 方式来互连 Go 程序的组件。 6 | 7 | 并发程序又许多规则;但是,最重要的规则是您应该避免共享,除非有万不得已的情况。并发程序中,共享数据是所有 bug 的根本原因。 8 | 9 | 从这章您必须记住尽管共享内存是在同一个进程的线程之上交换数据的唯一方法,但 Go 提供了更好的方法给每个 goroutine 来通信。因此,在你的代码里使用共享内存前,考虑一下 Go 的语法。虽然如此,如果您真的不得不使用共享内存,您可能会考虑使用监视 goroutine 来代替。 10 | 11 | 下章的主要话题是代码测试,代码优化和代码分析。除了这些主题,您会了解到基准测试,交叉编译和找出隐藏代码。 12 | 13 | 下章的最后,您也会了解到怎样文档化您的代码并使用 `godoc` 工具生成 HTML 输出。 -------------------------------------------------------------------------------- /eBook/chapter10/10.3.md: -------------------------------------------------------------------------------- 1 | # **goroutine超时检查的两种方式** 2 | 3 | 这节介绍两个非常重要的技巧来帮助您处理 goroutines 超时。简单说,这两个技巧帮您解决不得不一直等待一个 goroutine 完成它的工作,并且让您完全控制等待 goroutine 结束的时间。这两个技巧都使用方便的 `select` 关键字的功能并结合上节中使用过的 `time.After()` 函数。 -------------------------------------------------------------------------------- /eBook/chapter10/10.4.1.md: -------------------------------------------------------------------------------- 1 | # **信号通道** 2 | 3 | **信号通道** 是一个仅用来发送信号的通道。简单说,当您想要通知别人一些事情时可以使用信号通道。信号通道不能用来传输数据。 4 | 5 | > *您不能混淆信号通道和在[第8章](https://github.com/hantmac/Mastering_Go_ZH_CN/tree/master/eBook/chapter8/08.0.md)(Go UNIX系统编程)讨论的 **Unix 信号处理**,它们是完全不同的概念。* 6 | 7 | 在这章后面的 *指定 goroutines 的执行顺序* 一节,您将看到使用信号通道的代码例子。 8 | -------------------------------------------------------------------------------- /eBook/chapter10/10.4.3.md: -------------------------------------------------------------------------------- 1 | # **值为nil的通道** 2 | 3 | 这节,您将了解到 **值为 nil 的通道**。这些是通道的特殊类型,因为它们总是阻塞的。空通道的使用说明在 `nilChannel.go` 中, 分为四个代码片段来介绍。 4 | 5 | `nilChannel.go` 的第一部分如下: 6 | 7 | ```go 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | "math/rand" 13 | "time" 14 | ) 15 | ``` 16 | 17 | `nilChannel.go` 的第二段代码显示如下: 18 | 19 | ```go 20 | func add(c chan int) { 21 | sum := 0 22 | t := time.NewTimer(time.Second) 23 | for { 24 | select { 25 | case input := <-c: 26 | sum = sum + input 27 | case <-t.C: 28 | c = nil 29 | fmt.Println(sum) 30 | } 31 | } 32 | } 33 | ``` 34 | 35 | `add()` 函数展示了如何使用空通道。`<-t.c` 表达式按在 `time.NewTimer()` 调用中指定的时间阻塞 `t` 计时器的 `c` 通道。不要混淆函数的参数 `c` 通道和 `t` 计时器的 `t.c` 通道。它会触发 `select` 表达式的相关分支的执行,给 `c` 通道分配 `nil` 值并打印 `sum` 变量。 36 | 37 | `nilChannel.go` 的第三段代码如下: 38 | 39 | ```go 40 | func send(c chan int) { 41 | for { 42 | c <- rand.Intn(10) 43 | } 44 | } 45 | ``` 46 | 47 | `send()` 函数的目的是产生随机数并持续发送它们到一个通道里,只要这个通道是打开的。 48 | 49 | `nilChannel.go` 的其余代码如下: 50 | 51 | ```go 52 | func main() { 53 | c := make(chan int) 54 | go add(c) 55 | go send(c) 56 | time.Sleep(3 * time.Second) 57 | } 58 | ``` 59 | 60 | 使用 `time.Sleep()` 函数是为了给这俩个 goroutines 足够的操作时间。 61 | 62 | 执行 `nilChannel.go` 将产生如下输出: 63 | 64 | ```shell 65 | $go run nilChannel.go 66 | 13167523 67 | $go run nilChannel.go 68 | 12988362 69 | ``` 70 | 71 | 由于执行 `add()` 函数中的 `select` 表达式的第一个分支的次数不固定,所以您执行 `nilChannel.go` 会得到不同的结果。 72 | -------------------------------------------------------------------------------- /eBook/chapter10/10.4.md: -------------------------------------------------------------------------------- 1 | # **重温Channel(通道)** 2 | 3 | 一旦掌握了 `select` 关键字,Go channels 可以以几种独特的方式做更多事要比您在[第9章](https://github.com/hantmac/Mastering_Go_ZH_CN/tree/master/eBook/chapter9/09.0.md)(并发-Goroutines,Channel和Pipeline)学到的。这节将揭晓 Go channels 的这些使用方法。 4 | 5 | 要记住 channel 类型的零值是 `nil`,并且如果您发送一个消息给以关闭的 channel,程序将崩溃。然而,如果您尝试从已关闭的 channel 读取的话,会得到 channel 类型的零值。因此,关闭 channel 后,您不能再往里写,但您能一直读。 6 | 7 | 为了能关闭 channel, channel 不必是只接受。另外,一个 `nil` channel 总是阻塞的。channels 的这个特性非常有用,当您想要禁用 `select` 表达式的一个分支时,可以分配一个 `nil` 值给一个 channel 变量。 8 | 9 | 最后,如果您要关闭一个 `nil` channel,程序就会崩溃。最好的说明是下面这个 `closeNilChannel.go` 程序: 10 | 11 | ```go 12 | package main 13 | 14 | func main() { 15 | var c chan string 16 | close(c) 17 | } 18 | ``` 19 | 20 | 执行 `closeNilChannel.go` 产生如下输出: 21 | 22 | ```shell 23 | $go run closeNilChannel.go 24 | panic: close of nil channel 25 | 26 | goroutine 1 [running]: 27 | main.main() 28 | /Users/mtsouk/closeNilChannel.go:5 +0x2a 29 | exit status 2 30 | ``` -------------------------------------------------------------------------------- /eBook/chapter10/10.5.md: -------------------------------------------------------------------------------- 1 | # 通过共享变量来共享内存 2 | 3 | **通过共享变量来共享内存** 是 Unix 线程间彼此通信非常普通的方式。一个 **互斥** 变量是一个互相排斥变量的简称,它主要用于线程同步和在有多个写操作同时发生时保护共享数据。互斥工作类似于容量为一的 **缓冲通道**,它允许最多一个 goroutine 在任何给定时间访问共享变量。这就是说没有办法让俩个或更多 goroutines 同时去更新一个变量。 4 | 5 | 一个并发程序的 **关键部分** 是代码不能被所有进程,线程或如当前的所有 goroutines 同时执行。代码需要用互斥体保护起来。因此,识别代码的关键部分会使整个程序处理非常简单,您应该注意这个任务。 6 | 7 | > *当两个关键部分使用相同的 `sync.Mutex` 或 `sync.RWMutex` 变量时,您不能把其中一个嵌入另一个。不惜任何代价一定要避免跨函数传播互斥体,因为那会很难看出您是否做了嵌套。* 8 | 9 | 下面两小节将说明 `sync.Mutex` 和 `sync.RWMutex` 类型的使用。 -------------------------------------------------------------------------------- /eBook/chapter10/10.8.md: -------------------------------------------------------------------------------- 1 | # 延展阅读 2 | 3 | 下面是非常有用的资源: 4 | 5 | + 可以在[https://golang.org/pkg/sync/](https://golang.org/pkg/sync/)查看 `sync` 包文档。 6 | + 可以在[https://golang.org/pkg/context/](https://golang.org/pkg/context/)查看 `context` 包文档。 7 | + 访问[https://golang.org/src/runtime/proc.go](https://golang.org/src/runtime/proc.go)了解更多关于 Go 调度器多实现。 8 | + 可以在[](https://golang.org/s/go11sched)浏览 Go 调度器的设计文档。 -------------------------------------------------------------------------------- /eBook/chapter10/10.9.md: -------------------------------------------------------------------------------- 1 | # 练习 2 | 3 | + 使用缓冲通道实现一个并发版本的 `wc(1)`。 4 | + 接着,使用共享内存实现一个并发版本的 `wx(1)`。 5 | + 最后,使用监视 goroutine 实现一个并发版本的 `wx(1)`。 6 | + 修改 `workerPool.go` 的源码来保存结果到文件里。处理文件时,使用互斥锁和关键部分,或者一个监视 goroutine 来保证在磁盘上写入您的数据。 7 | + 当 `workerPool.go` 的 `size` 全局变量为 `1` 时会发生什么?为什么? 8 | + 修改 `workerPool.go` 的源码来实现 `wc(1)` 支持命令行功能。 9 | + 修改 `workerPool.go` 的源码来实现 `clients` 和 `data` 缓冲通道的大小可以通过命令行参数来定义。 10 | + 使用监视 goroutine 写一个并发版本的 `find(1)` 命令行工具。 11 | + 修改 `simpleContext.go` 源码,把在 `f1()`, `f2()`, `f3()` 中使用的匿名函数改为一个单独的函数。这个改动的难点是什么? 12 | + 修改 `simpleContext.go` 的源码,让 `f1()`,`f2()`,`f3()` 函数使用外部创建的 `Context` 变量而不是它们自己的。 13 | + 修改 `useContext.go` 源码,使用 `context.WithDeadline()` 或者 `context.WithCancel()` 来代替 `context.WithTimeout()`。 14 | + 最后,使用 `sync.Mutex` 互斥锁时间一个并发版本的 `find(1)` 命令行工具。 -------------------------------------------------------------------------------- /eBook/chapter11/11.0.md: -------------------------------------------------------------------------------- 1 | # **代码测试,优化以及分析** 2 | 3 | 上一章讨论了 Go 中的并发,和 `select` 语句允许您使用 channels 来控制 goroutines 并允许 goroutines 进行通信。 4 | 5 | 本章 Go 主题只是稍微高级点,而他们确非常实用和重要,特别是当您对改善您的 Go 程序性能感兴趣和快速发现 bug 时。这章主要解决代码优化,代码测试,代码文档化以及代码分析。 6 | 7 | **代码优化** 是开发人员试图使程序的某些部分运行的更快,更有效率,或实用较少的资源的过程。简单说,代码优化是消除一个程序的瓶颈。 8 | 9 | **代码测试** 是确保您的代码按照您设想的执行。这章,您将经历 Go 测试代码方式。写代码测试您的程序的最佳时期是开发阶段,因为这可以帮您尽早的发现 bug。 10 | 11 | **代码分析** 是为了获取代码运行方式的详细理解测量一个程序的某些方面。代码分析的结果可以帮助您决定您的代码哪些部分需要修改。 12 | 13 | 我希望您已经认识到您的代码文档化的重要性,以便描述您在开发您的程序的实现过程中所做的决策。这章,您将看到 Go 怎样帮您把您实现的模块生成文档。 14 | 15 | > *文档是非常重要的,以至一些开发者会先写文档再写代码* 16 | 17 | 这章,您将了解如下主题: 18 | 19 | + 分析 Go 代码 20 | + `go tool pprof` 工具 21 | + 使用 Go 分析器的 web 界面 22 | + 测试 Go 代码 23 | + `go test` 命令 24 | + `go tool trace` 工具 25 | + 基准化分析 Go 代码 26 | + 跨平台编译 27 | + 给您的 Go 代码生成文档 28 | + 创建例子函数 29 | + 在您的程序中找出不可到达的 Go 代码 30 | -------------------------------------------------------------------------------- /eBook/chapter11/11.1.1.md: -------------------------------------------------------------------------------- 1 | # **1.10和1.9的版本对比** 2 | 3 | 这章将列举 1.9 和 1.10 版本之间非常重要的不同点,只是让您了解 Go 变更的节奏。 4 | 5 | 1.10 版本的一些改变如下: 6 | 7 | + `GOROOT` 和 `GOTMPDIR` 环境变量的定义方式有所变化。 8 | + `go test` 命令缓存测试结果,意味着它会运行的快点。 9 | + `go doc` 工具现在包含了当您告诉 `go doc` 显示数据关于返回一个类型的切片或指向一个类型指针的函数输出。 10 | + 您将在本章稍后看到 `runtime/pprof` 包现在包含有关阻塞和互斥配置文件的符号信息。 11 | + `go fix` 工具替换 `golang.org/x/net/context` 的 `import` 声明为 `context`。 12 | + `go tool proff` 包含一个 web 界面。虽然这是一个重大的变化,但它与 Go 编程语言本身无关,因此不会破坏任何现有的 Go 代码。您将在本章稍后看到 web 界面的实际应用。 13 | + Go 1.10 版本对一些标准包做了微小改动,包括 `archive/tar` 和 `archive/zip`,`debug/macho`,`hash`,`html/template`,`match/big`,`net/url`,`os`,`time`,`unicode` 和 `net/smtp`。 14 | 15 | 如您认识到的,Go 编程语言的发展没有破坏任何东西。起初这可能看起来无关紧要,但它是 Go 的一个非常重要的特性,它保证了现有的 Go 代码将在 Go 的发展过程中不做任何修改仍能继续编译。这样的一个副作用是这本书将涉及多年的知识点。 -------------------------------------------------------------------------------- /eBook/chapter11/11.1.md: -------------------------------------------------------------------------------- 1 | # **本章使用的Go版本** 2 | 3 | 注意这章,我们将在 macOS 机器上使用最新的 Go 版本。编辑本书时,Go 版本是 1.10: 4 | 5 | ```shell 6 | $ date 7 | Fri Mar 9 23:17:49 EET 2018 8 | $ go version 9 | go version go1.10 darwin/amd64 10 | ``` 11 | 12 | 我提及您至少需要 Go 版本是 1.10 的原因是为了能使用 Go 代码分析器的 web 界面。然而,其余介绍的命令和代码与早期的 Go 版本仍能正常工作。 -------------------------------------------------------------------------------- /eBook/chapter11/11.10.md: -------------------------------------------------------------------------------- 1 | # **揪出隐藏的代码** 2 | 3 | 不能执行的 Go 代码是逻辑错误,因此由开发者或一个 Go 编译器的正常执行操作来解决这个问题是相当困难的。简单讲,除了无法执行此代码外,对于隐藏代码没有任何问题! 4 | 5 | 看一下下面保存在 `cannotReach.go` 中的代码: 6 | 7 | ```go 8 | package main 9 | import ( 10 | "fmt" 11 | ) 12 | 13 | func f1() int { 14 | fmt.Println("Entering f1()") 15 | return -10 16 | fmt.Println("Exiting f1()") 17 | return -1 18 | } 19 | 20 | func f2() int { 21 | if true { 22 | return 10 23 | } 24 | fmt.Println("Exiting f2()") 25 | return 0 26 | } 27 | 28 | func main() { 29 | fmt.Println(f1()) 30 | fmt.Println("Exiting program...") 31 | } 32 | ``` 33 | 34 | `cannotReach.go` 的代码没有语法错误。因此,您可以执行 `cannotReach.go`,编译器不会报任何错误: 35 | 36 | ```shell 37 | $ go run cannotReach.go 38 | Entering f1() 39 | -1 40 | Exiting program... 41 | ``` 42 | 43 | 注意程序中的 `f2()` 从来没有被执行。然而,这很容易猜到下面的 `f2()` 没有执行的原因是之前的 `if` 语句总是 `true`: 44 | 45 | ```go 46 | fmt.Println("Exiting f2()") 47 | return 0 48 | ``` 49 | 50 | 因此,对于这个问题您能做什么呢?您可以执行下面的 `go tool vet` : 51 | 52 | ```shell 53 | $ go tool vet cannotReach.go 54 | cannotReach.go:10: unreachable code 55 | ``` 56 | 57 | 这个输出告诉我们有不可到达代码在程序的第10行。现在我们来从函数 `f1()` 中移除 `return -10` 语句,再执行 `go tool vet`: 58 | 59 | ```shell 60 | $ go tool vet cannotReach.go 61 | ``` 62 | 63 | 这里没有新的错误信息,尽管在 `f2()` 函数中仍有隐藏代码。这意味着 `go tool vet` 无法捕获每种可能的逻辑错误。 -------------------------------------------------------------------------------- /eBook/chapter11/11.14.md: -------------------------------------------------------------------------------- 1 | # **延展阅读** 2 | 3 | 访问如下 web 链接: 4 | 5 | + 访问 Graphviz 网站[http://graphviz.org](http://graphviz.org) 6 | + 访问 `testing` 包的文档页,可在[https://golang.org/pkg/testing](https://golang.org/pkg/testing)找到 7 | + 您可以访问 `godoc` 工具的文档页[https://godoc.org/golang.org/x/tools/cmd/godoc](https://godoc.org/golang.org/x/tools/cmd/godoc)了解它的更多内容 8 | + 访问 `runtime/pprof` 标准包的文档页,可以在[https://golang.org/pkg/runtime/pprof](https://golang.org/pkg/runtime/pprof)找到 9 | + 您可以访问[https://golang.org/src/net/http/pprof/pprof.go](https://golang.org/src/net/http/pprof/pprof.go)浏览 `net/http/pprof`包的源码 10 | + 您可以在[https://golang.org/src/net/http/pprof/](https://golang.org/src/net/http/pprof/)找到 `net/http/pprof`包的文档页 11 | + Go1.10 版本和 Go1.9 版本的完整变更列表,您可以查看[https://golang.org/doc/go1.10](https://golang.org/doc/go1.10) 12 | + 您可以访问 `pprof` 工具的开发页[https://github.com/google/pprof](https://github.com/google/pprof)了解它的更多内容 13 | + 在[https://www.youtube.com/watch?=v=8hQG7QlcLBk](https://www.youtube.com/watch?=v=8hQG7QlcLBk)观看 GohperCon 2017 大会上由 Mitchell Hashimoto 介绍的 Go 语言高级测试视频 14 | + 您可以在[https://golang.org/src/testing/testing.go](https://golang.org/src/testing/testing.go)找到 `testing`包的源码 15 | + 您可以访问 `profile` 包的 web 页面[https://github.com/pkg/profile](https://github.com/pkg/profile)了解它的更多内容 16 | + 你可以访问 `go fix` 工具的 web 页面[https://golang.org/cmd/fix](https://golang.org/cmd/fix)了解它的更多内容 -------------------------------------------------------------------------------- /eBook/chapter11/11.15.md: -------------------------------------------------------------------------------- 1 | # **练习** 2 | 3 | + 给我们在[第8章](https://github.com/hantmac/Mastering_Go_ZH_CN/tree/master/eBook/chapter8/8.0.md)(*Go UNIX系统编程*)开发的 `byWord.go` 程序写测试函数。 4 | + 给我们在[第8章](https://github.com/hantmac/Mastering_Go_ZH_CN/tree/master/eBook/chapter8/8.0.md)(*Go UNIX系统编程*)开发的 `readSize.go` 程序写基准函数。 5 | + 试着修改 `documentMe.go` 和 `documentMe_test.go` 代码中的问题。 6 | + 使用 `go tool pprof` 工具的文本接口来检查由 `profileMe.go` 生成的 `memoryProfile.out` 文件。 7 | + 接下来,使用 `go tool pprof` 工具的 web 接口来检查由`profileMe.go` 生成的 `memoryProfile.out` 文件。 -------------------------------------------------------------------------------- /eBook/chapter11/11.16.md: -------------------------------------------------------------------------------- 1 | # **本章小节** 2 | 3 | 在这章,我们讨论了代码测试,代码优化和代码分析。到本章为止,您了解了如何找到隐藏代码和怎样交叉编译 Go 代码。`go test` 命令用来测试和基准测试 Go 代码,以及使用例子函数提供而外的文档。 4 | 5 | 尽快 Go 分析器和 `go tool trace` 的讨论远没完成,但您应该理解了分析和代码追踪等话题,没有什么可以取代您自己的实验并尝试新技能。 6 | 7 | 下一章,我们将开始讨论 Go 语言的网络编程,涉及编写运行在 TCP/IP 计算机网络,也包括互联网上的应用程序。下章的部分主题是 `net/http` 包,用 Go 创建 web 客户端和 web 服务器,`http.Response` 和 `http.Request` 结构,分析 HTTP 服务器,和网络连接超时。 8 | 9 | 另外,下章将讨论 **IPv4** 和 **IPv6** 协议以及 Wireshark 和 tshark 工具,它们用于捕获和分析网络流量。 -------------------------------------------------------------------------------- /eBook/chapter11/11.2.md: -------------------------------------------------------------------------------- 1 | # **安装beta或者RC版本** 2 | 3 | 如果您热衷于尝试 Go 的最新版本,即使这意味着您需要安装一个测试版或**候选版本**(RC),有一个办法! 4 | > *尽管他们的命名(候选版)是相当稳定。但不要在没有很恰当理由的情况下安装一个 RC 版在生产级 Uninx 机器上!* 5 | 6 | 如果您的 Go 版本比 1.10 早,并想要尝试 1.10 RC1 版本,您可以按如下操作: 7 | 8 | ```shell 9 | $ go get golang.org/x/build/version/go1.10rc1 10 | ``` 11 | 12 | 如果您想安装不同的版本,您应该期望执行一个类似的命令。在 macOs High Sierra 系统上运行发布版 10.13.3,这个新的 Go 执行文件将被安装在 `~/go/bin`: 13 | 14 | ```shell 15 | $ cd ~/go/bin 16 | $ ls -l 17 | -rwxr-xr-x 1 mtsouk staff 6051164 Jan 30 19:04 go1.10rc1 18 | ``` 19 | 20 | 如果您尝试执行 `go1.10rc1`,您将得到如下输出: 21 | 22 | ```shell 23 | $ ./go1.10rc1 24 | go1.10rc1: not downloaded. Run 'go1.10rc1 download' to install to /Users/mtsouk/sdk/go1.10rc1 25 | ``` 26 | 27 | 接下来您必须执行 1.10 RC1 的其余文件如下: 28 | 29 | ![](https://github.com/hantmac/Mastering_Go_ZH_CN/tree/master/images/chapter11/11.2.jpg) 30 | 31 | 您现在可以使用 `go1.10rc1` 运行 1.10 RC1 版本了: 32 | 33 | ```shell 34 | $ ~/go/bin/go1.10rc1 version 35 | go version go1.10rc1 darwin/amd64 36 | ``` 37 | -------------------------------------------------------------------------------- /eBook/chapter11/11.3.md: -------------------------------------------------------------------------------- 1 | # **关于优化** 2 | 3 | 代码优化是艺术和科学的结合!这意味着没有确定的方法来帮助您优化您的 Go 代码或任何其他编程语言代码,并且如果您想使您的代码运行的更快,您应该多动脑尝试多种方法。 4 | 5 | > *您应该确保您优化的代码没有任何 bug,因为优化 bug 没有意义。如果您的程序有任何 bug ,您应该先 debug!* 6 | 7 | 如果您真的投入代码优化,您可能想读一下由 *Alfred V.Aho, Monica S.Lam, Ravi Sethi 和 Jeffrey D.Ullman 编写, Pearson Education Limited, 2014 出版的编译器:原理,技术和工具*一书,它侧重于编译器构造。另外,由 *Donald Knuth, Addison-Wesley 教授, 1998 写的计算机编程艺术*系列全书对于编程的方方面面是非常棒的资源。 8 | 9 | 要一直记着 *Donald Knuth* 关于优化的建议: 10 | 11 | > *真正的问题是程序员花费太多时间来担心效率在错误的地方和时间;过早优化是编程的万恶之源(至少是大部分)* -------------------------------------------------------------------------------- /eBook/chapter11/11.4.md: -------------------------------------------------------------------------------- 1 | # **优化你的Go代码** 2 | 3 | 代码优化是这样的一个过程,试图找出代码中对整个程序性能有重大影响的部分,以使它们运行的更快或使用更少的资源。 4 | 5 | 本章后面出现的基准测试部分将极大地帮助您了解代码运行背后的情况,以及哪些程序参数对程序性能的影响最大。 6 | 7 | 然而,不要低估正常情形。简单说,如果您的程序中的某个函数比其他函数多执行了一万次,那就先试着优化这个函数。 8 | 9 | > *对于优化通常的建议是您必须优化没有 bug 的代码。意思是您必须优化可运行的代码。因此,您应该首先把代码写正确即便它运行的慢。最后,程序员最常犯的一个错误是试图优化代码的第一个版本,这是大多 bug 的根源* 10 | 11 | 再次,代码优化是艺术和科学的结合,这意味着这是相当困难的任务。下节关于分析 Go 代码将绝对能帮助您进行代码优化,因为分析的主要目的是找到代码的瓶颈,以便优化程序中正确的和最重要的部分。 -------------------------------------------------------------------------------- /eBook/chapter11/11.5.1.md: -------------------------------------------------------------------------------- 1 | # *标准库net/http/pprof* 2 | 3 | 虽然 Go 附带了低级别的 `runtime/pprof` 标准包,但也有一个高级的 `net/http/pprof` 包,当您想要分析一个 Go 写的 web 应用时应该使用它。 由于本章不讨论用 Go 创建 HTTP 服务器,所以您将在[第12章](https://github.com/hantmac/Mastering_Go_ZH_CN/tree/master/eBook/chapter12/12.0.md)(Go网络编程基础)进一步了解 `net/http/pprof` 包。 -------------------------------------------------------------------------------- /eBook/chapter11/11.5.4.1.md: -------------------------------------------------------------------------------- 1 | # **使用web接口的分析示例** 2 | 3 | 我们将使用从 `profileMe.go` 运行捕获的数据来学习 Go 分析器的 web 接口,因为不需要专门创建一个代码示例来做这个事。如您在之前小节了解到的,您首先需要执行如下命令: 4 | 5 | ```shell 6 | $ go tool pprof -http=localhost:8080 /tmp/cpuProfile.out 7 | Main binary filename not available. 8 | ``` 9 | 10 | 下图显示了执行上面命令后, Go 分析器 web 用户接口的初始界面: 11 | 12 | ![运行中的Go分析器 web 接口](https://github.com/hantmac/Mastering_Go_ZH_CN/tree/master/images/chapter11/11.5.4.1-1.jpg) 13 | 14 | 同样,下图显示了 Go 分析器的 `http://localhost:8080/source` URL内容,显示了程序的每个函数的分析信息: 15 | 16 | ![](https://github.com/hantmac/Mastering_Go_ZH_CN/tree/master/images/chapter11/11.5.4.1-2.jpg) -------------------------------------------------------------------------------- /eBook/chapter11/11.5.4.2.md: -------------------------------------------------------------------------------- 1 | # **Graphviz快览** 2 | 3 | **Graphviz** 是一个非常方便的实用程序汇编和计算机语言,允许您绘制复杂的图形。严格讲,Graphviz 是一个用于操纵有向和无向**图形**结构以及生成图形布局的工具集合。Graphviz 有它自己的语言(命名为 **DOT**),该语言简单,优雅并且强大。Graphviz 的优点是您可以实用一个简单的文本编辑器来写它的代码。该特点的一个很棒的作用是您可以容易的开发生成 Graphviz 代码的脚本!此外,大多数编程语言,包括 **Python,Ruby,C++ 和 Perl**,都提供了自己的接口,用于实用原生代码创建 Graphviz 文件。 4 | 5 | > 您不需要了解 Graphviz 为使用 Go 分析器的 web 接口的所有事情。只要了解 Graphviz 怎样工作和它的代码长什么样就可以了。 6 | 7 | 下面是保存在 `graph.dot` 中的 Graphviz 代码,简要的说明了 Graphviz 工作方式和 Graphviz 语言的样子: 8 | 9 | ![](https://github.com/hantmac/Mastering_Go_ZH_CN/tree/master/images/chapter11/11.5.4.2.jpg) 10 | 11 | `color` 属性改变一个节点的颜色,而 `shape` 属性改变节点的形状。另外,`dir` 属性可以应用到边,定义一条边是否有俩个箭头,一个箭头或没有箭头。此外,箭头样式可使用 `arrowhead` 和 `arrowtail` 属性定义。 12 | 13 | 使用一个 Graphviz 命令行工具编译上面的代码来创建一个 PNG 图片,需要在您喜爱的 Unix shell 中执行如下命令: 14 | 15 | ```shell 16 | $ dot -T png graph.dot -o graph.png 17 | $ ls -l graph.png 18 | -rw-r--r--@ 1 mstouk staff 94155 Mar 1 07:30 graph.png 19 | ``` 20 | 21 | 下图显示了由执行上面命令产生的图形文件: 22 | 23 | ![使用Graphviz创建图形](https://github.com/hantmac/Mastering_Go_ZH_CN/tree/master/images/chapter11/11.5.4.2.jpg) 24 | 25 | 因此,如果您想要可视化任何类型的结构,您一定要考虑使用 Graphviz 及其工具,特别是如果您想使用自己的脚本自动化。 26 | 27 | 28 | -------------------------------------------------------------------------------- /eBook/chapter11/11.5.4.md: -------------------------------------------------------------------------------- 1 | # **Go分析器的web接口** 2 | 3 | Go 1.10 版本带来的好消息是 `go tool pprof` 命令提供了一个 web 用户接口! 4 | 5 | > *为了这个 web 用户接口正常工作,您需要安装 **Graphviz**,而且您的 web 浏览器必须支持 JavaScript。如果您想运行的安全,就使用 **Chrome** 或 **Firefox** *。 6 | 7 | 您可以使用如下命令启动交互式 Go 分析器: 8 | 9 | ```shell 10 | $ go tool pprof -http=[host]:[port] aProfile 11 | ``` -------------------------------------------------------------------------------- /eBook/chapter11/11.5.md: -------------------------------------------------------------------------------- 1 | # *分析Go代码* 2 | 3 | 分析是一个动态程序分析的过程,用于衡量与程序执行相关的各种值,以便您更好地了解程序的行为。在这节,您将了解怎样分析 Go 代码,以便更好的理解代码并改善它的性能。有时,代码分析甚至能发现 bug! 4 | 5 | 首先,我们使用 Go 分析器的命令行界面。接下来,我们 Go 分析器的全新 web 界面! 6 | 7 | 你要分析 Go 代码,最重要的一点要记住的是,需要直接或间接的引入 `runtime/pprof` 标准库。 您可以通过执行 `go tool pprof --help` 命令,这个命令将产生需要输出,从中找到 `pprof` 工具的帮助文档。 -------------------------------------------------------------------------------- /eBook/chapter11/11.7.md: -------------------------------------------------------------------------------- 1 | # **测试** 2 | 3 | 软件测试一个非常大的主题,而且它不能被一本书中的一章的单独一节所涵盖。因此,这简要的部分将介绍尽可能多的实用信息。 4 | 5 | Go 允许您为您的代码编写测试来发现缺陷。严格讲,这节是关于自动**测试**的,包含写额外代码来验证真实代码;即产品代码,是否按预期运行。因此,一个测试函数的结果是不是 `PASS` 就是 `FAIL`。很快您将看到它是怎么运作的。 6 | 7 | 虽然 Go 的测试方法起初可能看起来很简单,特别是如果您将它与其他编程语言的测试实践进行比较,它非常高效和有效,因为它不需要占用开发者的太多时间。 8 | 9 | Go 遵循有关测试的某些约定。首先,测试函数应该写在以 `_test.go` 结尾的 Go 源码中。因此,如果您有一个名为 `aGoPackage.go` 的包,那么您的测试代码应该放在名为 `aGoPackage_test.go` 的文件中。测试函数以 `Test`开头,并检查生产包的功能行为的正确性。 10 | 11 | 最后,您需要引入 `testing` 标准包以便 `go test` 子命令正确运行。如您马上看到的,这个引入要求也适用于另外两种情况。 12 | 13 | 一旦测试代码正确,`go test` 子命令为您做了所有脏活,包括为特定函数扫描所有 `*_test.go` 文件,生成一个临时的正确 `main` 包来调用这些特定函数,获得结果并产生最终输出。 14 | 15 | > *总是把测试代码放在另一个源文件。没必要创建一个难以阅读和维护的庞大源文件。* -------------------------------------------------------------------------------- /eBook/chapter11/11.8.2.md: -------------------------------------------------------------------------------- 1 | # **错误的基准测试函数** 2 | 3 | 看一下下面的基准测试函数代码: 4 | 5 | ```go 6 | func BenchmarkFiboI(b *testing.B) { 7 | for i := 0; i < b.N; i++ { 8 | _ = fibo1(i) 9 | } 10 | } 11 | ``` 12 | 13 | `BenchmarkFibo()` 函数有一个有效的方法名和正确的签名。然而,坏消息是这个基准测试函数是错的,并且您执行 `go test` 命令后不能从它获得任何输出。 14 | 15 | 原因是根据上一节的描述,随着 `b.N` 值的增加,由于 `for`循环这个基准测试函数的运行次数也会增加。这一事实阻止了 `BenchmarkFiboI()` 收敛于一个稳定的数字,从而妨碍了函数完成并返回。 16 | 17 | 由于算法原因,下面的基准测试函数也实现错了: 18 | 19 | ```go 20 | func BenchmarkfiboII(b *testing.B) { 21 | for i := 0 ; i < b.N ; i++ { 22 | _ = fibo2(b.N) 23 | } 24 | } 25 | ``` 26 | 27 | 相反,下面俩个基准测试函数的实现没有错误: 28 | 29 | ```go 30 | func BenchmarkFiboIV(b *testing.B) { 31 | for i := 0; i < b.N; i++ { 32 | _ = fibo3(10) 33 | } 34 | } 35 | 36 | func BenchmarkFiboIII(b *testing.B) { 37 | _ = fibo3(b.N) 38 | } 39 | ``` -------------------------------------------------------------------------------- /eBook/chapter11/11.8.md: -------------------------------------------------------------------------------- 1 | # **基准测试** 2 | 3 | 基准测试能给您一个函数或一个程序的性能信息,从而更好的理解一个函数比另一个函数是更快还是更慢,或者和一个应用的其他部分比较。使用这些信息,您可以容易的发现需要重写来提升性能的代码部分。 4 | 5 | > *绝对不要在一个繁忙的,当前正运行其他程序的 Unix 机器上给您的 Go 代码做基准测试,除非为了更重要的目的您有不得已的理由。* 6 | 7 | Go 遵循有关基准测试的某些规则。最为重要的规则是一个基准测试函数的命名必须用 `Benchmark` 开头。 8 | 9 | 再次说明,`go test` 子命令是负责一个程序的基准测试。因此,您仍需要引入 `testing` 标准包并需要把基准测试函数放入以 `_test.go` 结尾的 Go 文件中。 -------------------------------------------------------------------------------- /eBook/chapter12/12.0.md: -------------------------------------------------------------------------------- 1 | # **Go网络编程基础** 2 | 3 | 在前一章中,我们讨论了使用```benchmark```函数对Go代码进行性能测试、如何为Go代码编写单元测试、示例函数的编写、交叉编译和Go代码的调优,以及如何生成Go代码的文档。 4 | 5 | 本章主要介绍Go语言的网络编程,包括如何创建Web应用程序,并使其可以在计算机网络或互联网上运行。在下一章则介绍如何开发TCP和UDP的应用程序。 6 | 7 | 为了顺利地完成本章和下一章的内容,本章还介绍一些关于HTTP协议、网络以及网络工作原理的知识。 8 | 9 | 在这一章中,将学习以下主题: 10 | 11 | - TCP/IP简介及其重要性 12 | - IPv4和IPv6相关协议 13 | - 命令行工具**netcat** 14 | - 在Go中实现**DNS**查询 15 | - ```net/http```包简介 16 | - ```http.Response```、```http.Request```和```http.Transport```结构简介 17 | - 使用Go创建Web服务器 18 | - 使用Go进行Web客户端编程 19 | - 使用Go创建网站 20 | - ```http.NewServeMux```类型介绍 21 | - **Wireshark**和**tshark**介绍 22 | - HTTP连接的超时处理(客户端和服务端) 23 | 24 | 对于本章介绍的一些底层知识相对独立,可以跳过学习——在需要的时候可以重新复习这些内容。 25 | -------------------------------------------------------------------------------- /eBook/chapter12/12.1.1.md: -------------------------------------------------------------------------------- 1 | # **```http.Response```类型** 2 | 3 | 在文件[https://golang.org/src/net/http/response.go](https://golang.org/src/net/http/response.go)中可以找到```http.Response```结构的定义如下: 4 | 5 | > ```go 6 | > type Response struct { 7 | > Status string // e.g. "200 OK" 8 | > StatusCode int // e.g. 200 9 | > Proto string // e.g. "HTTP/1.0" 10 | > ProtoMajor int // e.g. 1 11 | > ProtoMinor int // e.g. 0 12 | > Header Header 13 | > Body io.ReadCloser 14 | > ContentLength int64 15 | > TransferEncoding []string 16 | > Close bool 17 | > Uncompressed bool 18 | > Trailer Header 19 | > Request *Request 20 | > TLS *tls.ConnectionState 21 | > } 22 | > ``` 23 | 24 | 这个复杂的```http.Response```类型可以用来表示HTTP请求的响应。这个结构的每个字段,都可以在以上的源文件找到更多的信息。在标准Go库中,大多数```struct```类型都是基于一个结构,以及与结构字段相关的函数操作。 25 | -------------------------------------------------------------------------------- /eBook/chapter12/12.1.2.md: -------------------------------------------------------------------------------- 1 | # **```http.Request```类型** 2 | 3 | ```http.Request```类型的作用是表示HTTP请求,该类型可以用于表示服务器接收的请求,或在HTTP客户端即将发送到服务器的请求。 4 | 5 | 源代码[https://golang.org/src/net/http/request.go](https://golang.org/src/net/http/request.go)中定义的```http.Request```结构类型如下: 6 | 7 | > ```go 8 | > type Request struct { 9 | > Method string 10 | > URL *url.URL 11 | > Proto string // "HTTP/1.0" 12 | > ProtoMajor int // 1 13 | > ProtoMinor int // 0 14 | > Header Header 15 | > Body io.ReadCloser 16 | > GetBody func() (io.ReadCloser, error) 17 | > ContentLength int64 18 | > TransferEncoding []string 19 | > Close bool 20 | > Host string 21 | > Form url.Values 22 | > PostForm url.Values 23 | > MultipartForm *multipart.Form 24 | > Trailer Header 25 | > RemoteAddr string 26 | > RequestURI string 27 | > TLS *tls.ConnectionState 28 | > Cancel <-chan struct{} 29 | > Response *Response 30 | > ctx context.Context 31 | > } 32 | > ``` -------------------------------------------------------------------------------- /eBook/chapter12/12.1.md: -------------------------------------------------------------------------------- 1 | # **关于```net/http```,```net```和```http.RoundTripper```** 2 | 3 | 本章的核心是```net/http```包,它提供了用于开发强大的Web客户端和服务端的函数功能。在这个包中,```http.Get()```和```https.Get()```方法作为客户端,可以用来发送HTTP和HTTPS请求,而```http.ListenAndServe()```函数可用于创建Web服务器,并且指定服务器监听的IP地址和TCP端口号,然后在该函数中处理传入的请求。 4 | 5 | 除了```net/http```包,我们还在本章介绍的一些程序中使用```net```包。在第13章*网络编程-构建服务器与客户端*中,将会详细的介绍```net```包的功能。 6 | 7 | 最后,**接口**```http.RoundTripper```可以使Go的元素能够很方便的拥有执行HTTP事务的能力。简单地说,这意味着Go元素可以为```http.Request```返回```http.Response```结构。稍后将详细介绍```http.Response```和```http.Request```结构。 8 | -------------------------------------------------------------------------------- /eBook/chapter12/12.10.1.md: -------------------------------------------------------------------------------- 1 | # **SetDeadline 介绍** 2 | 3 | `net` 包使用 `SetDeadline()` 函数设置给定网络连接的读写截止时间。由于 `SetDeadline()` 函数的工作方式,您需要在任何读写操作前调用 `SetDeadline()`。请记住,Go 使用截止日期来实现超时,因此您不需要在应用程序每次接收或发送任何数据时重置它。 -------------------------------------------------------------------------------- /eBook/chapter12/12.11.md: -------------------------------------------------------------------------------- 1 | # **抓包工具Wireshark和tshark** 2 | 3 | 这节将简单的提及强大的 Wireshark 和 tshark 工具。**Wireshark** 是一个图形应用,是分析任何类型的网络流量的主流工具。尽管 Wireshark 非常强大,但有时您可能需要一个非图形界面的,可远程执行的轻量级应用。这种情况下,您可以使用 **tshark**,它是 Wireshark 的命令行版本。 4 | 5 | 很遗憾,Wireshark 和 tshark 的讨论超出了本章的范畴。 6 | -------------------------------------------------------------------------------- /eBook/chapter12/12.12.md: -------------------------------------------------------------------------------- 1 | # **延展阅读** 2 | 3 | 下面的资料一定会扩展您的视野,所以请找时间看一下: 4 | 5 | + Apache web 服务器的官方网站[http://httpd.apache.org](http://httpd.apache.org)。 6 | + Nginx web 服务器的官方网站[http://nginx.org](http://nginx.org)。 7 | + 您可能希望了解更多关于网络,TCP/IP 和它的各种服务,可以从阅读 **RFC** 文档开始。您可以在[http://www.rfc-archive.org](http://www.rfc-archive.org)上找到此类文档。 8 | + 浏览 Wireshark 和 tshark 的网站[https://www.wireshark.org/](https://www.wireshark.org/)了解更多信息。 9 | + 浏览 `net` 标准包文档,在[https://golang.org/pkg/net/](https://golang.org/pkg/net/)。它是 Go 官方文档中最大的之一。 10 | + 浏览 `net/http` 包文档[https://golang.org/pkg/net/http/](https://golang.org/pkg/net/http/) 11 | + 如果您不想写任何 Go 代码就创建一个网站,您可以试一试 **Hugo utility**,它是用 Go 写的!您可以在[https://gohugo.io](https://gohugo.io)(https://gohugo.io)了解更多关于 Hugo 框架。然而,对于每一个 Go 程序员真正有趣和有教育意义的是浏览它的源码,它在[https://github.com/gohugoio/hugo](https://github.com/gohugoio/hugo)。 12 | + 您可以在[https://golang.org/pkg/net/http/httptrace/](https://golang.org/pkg/net/http/httptrace/)浏览 `net/http/httptrace` 文档。 13 | + 您可以在[https://golang.org/pkg/net/http/pprof/](https://golang.org/pkg/net/http/pprof/)找到 `net/http/pprof` 文档。 14 | + 浏览 `nc(1)` 命令行工具的手册了解更多它的能力和各种命令行选项。 15 | + 您可以在[https://github.com/davecheney/httpstat](https://github.com/davecheney/httpstat)找到由 Dave Cheney 开发的 `httpstat` 工具。它是使用 `net/http/httptrace` 包追踪 HTTP 最好的例子。 16 | + 您可以浏览 `ab(1)` 手册[https://httpd.apache.org/docs/2.4/programs/ab.html](https://httpd.apache.org/docs/2.4/programs/ab.html)找到更多关于它的信息。 -------------------------------------------------------------------------------- /eBook/chapter12/12.13.md: -------------------------------------------------------------------------------- 1 | # **练习** 2 | 3 | + 自己不看这章的代码用 Go 写个 web 客户端 4 | + 合并 `MXrecords.go` 和 `NSrecords.go` 的代码,创建一个基于命令行参数具备全部功能的单独程序 5 | + 修改 `MXrecords.go` 和 `NSrecords.go` 的代码,使其也能接收 IP 地址作为输入 6 | + 修改 `advancedWebClient.go` 使其保存 HTML 输出到一个外部文件 7 | + 试着使用 goroutines 自己写个简单版本的 `ab(1)` 8 | + 修改 `kvWeb.go` 使其支持在 key-value 存储的原来版本中的 `DELETE` 和 `LOOKUP` 操作 9 | + 修改 `httpTrace.go` 使其有个标志能禁用 `io.Copy(os.Stdout, response.Body)` 表达式的执行 -------------------------------------------------------------------------------- /eBook/chapter12/12.14.md: -------------------------------------------------------------------------------- 1 | # **本章小结** 2 | 3 | 本章讨论了用于 web 客户端和 web 服务器编程以及用 Go 创建网站的 Go 代码!您也了解了允许您定义 HTTP 连接参数的 `http.Response`,`http.Request` 和 `http.Transport` 结构。 4 | 5 | 另外,您也了解到怎样使用 Go 代码获取 Unix 机器的网络配置和怎样使用 Go 程序执行 DNS 查询,包括获取一个域名的 NS 和 MX 记录。 6 | 7 | 最后,我们讨论了 **Wireshark** 和 **tshark**,这俩个非常流行的工具可以让您捕获和(最重要的)分析网络流量。在这章开始,我们也提及了 `nc(1)` 工具。 8 | 9 | 这本书的最后章节,我们将继续讨论 Go 语言的网络编程。而这次,我们将介绍低级别的 Go 代码,它可以让您开发 TCP 客户端和服务器以及 UDP 客户端和服务进程。另外,您将了解到创建 RCP 客户端和服务器。希望您会喜欢! -------------------------------------------------------------------------------- /eBook/chapter12/12.2.md: -------------------------------------------------------------------------------- 1 | # **关于TCP/IP** 2 | 3 | **TCP/IP**是保障互联网运行的一组基础协议。它的名字来自它最著名的两个协议:**TCP**协议和**IP**协议。 4 | 5 | **TCP**协议的全称是**传输控制协议(Transmission Control Protocol)**。TCP软件使用称为TCP报文的数据段,在机器之间传输数据。TCP协议可靠得传输能力是其主要的特点,也就是说在不需要程序员进行额外编码的情况下,该协议可以确保发送的数据包送达接收方。如果数据包发送没有被确认,TCP协议将重新发送该数据包。也就是说,TCP协议可以用于建立连接、传输数据、发送确认和关闭连接。 6 | 7 | 当两台主机之间建立TCP连接时,这两台机器之间会创建一个与电话呼叫类似的全双工虚拟链路。这两台主机会通过不断地通信,以确保数据发送和接收正确。如果由于某种原因连接中断,两台主机都会向上层应用程序返回错误。 8 | 9 | **IP**协议的全称是**Internet协议(Internet Protocol)**。IP协议本质上不是一个可靠的协议。IP协议通过封装通过TCP/IP网络传输的数据,根据IP地址将数据报文从源主机传送到目标主机。IP协议还具备将数据报文有效发送到目的地的寻址方法。尽管路由器作为专用设备执行IP路由转发,但每个TCP/IP设备都或多或少执行一些基本的路由转发。 10 | 11 | **UDP**协议的全称是**用户数据报协议(User Datagram Protocol)**,该协议基于IP协议,因此不确保可靠传输。简而言之,UDP协议比TCP协议要简单,因为该协议从设计上就没有考虑可靠性。因此,UDP消息可能会丢失、重传或乱序。此外,UDP数据报文的到达速度可以比接收方的处理能力快。因此当性能比可靠性更重要时,更多使用UDP协议。 12 | -------------------------------------------------------------------------------- /eBook/chapter12/12.3.md: -------------------------------------------------------------------------------- 1 | # **关于IPv4和IPv6** 2 | 3 | **IP协议**的第一个版本称为**IPv4**;为表示区分,最新版本的IP协议被称为**IPv6**。 4 | 5 | 当前IPv4协议的主要问题是IP地址即将耗尽,这也是创建IPv6协议的主要原因。IPv4协议地址耗尽的原因是一个IPv4地址只使用32位来表示,它可以表示出2的32次方(4294967296)个不同的IP地址。而IPv6使用128位定义一个地址。 6 | 7 | IPv4地址的格式为```10.20.32.245```(用点分隔的四段),而IPv6地址的格式为```3fce:1706:4523:3:150:f8ff:fe21:56cf```(用冒号分隔的八段)。 -------------------------------------------------------------------------------- /eBook/chapter12/12.4.md: -------------------------------------------------------------------------------- 1 | # **命令行工具netcat** 2 | 3 | 命令行工具```nc(1)```,全称```netcat(1)```,在测试TCP/IP的客户端和服务端时非常便利。本节将介绍它的一些常见用法。 4 | 5 | ```nc(1)```可以作为TCP服务的客户端使用,例如,作为客户端连接监听在端口```1234```的服务器主机```10.10.1.123```,命令如下: 6 | 7 | > ```shell 8 | > nc 10.10.1.123 1234 9 | > ``` 10 | 11 | 命令行工具```nc(1)```默认使用TCP协议。如果使用UDP协议,可以在执行```nc(1)```命令时携带```-u```参数。 12 | 13 | 如果要使用```netcat(1)```模拟服务器,可以携带```-l```参数,```netcat(1)```将监听指定端口号的连接。 14 | 15 | 如果希望```netcat(1)```生成详细的输出,可以使用```-v```和```-vv```参数,这些输出对排查网络连接故障提供了很大的便利。 16 | 17 | ```netcat(1)```不仅可以测试HTTP应用程序,在第13章*网络编程 - 构建服务器与客户端*中,它同样可以灵活的使用,用于开发TCP和UDP协议的客户机和服务器。在本章中后续的一个例子中,````netcat(1)```将作为案例使用。 -------------------------------------------------------------------------------- /eBook/chapter12/12.9.md: -------------------------------------------------------------------------------- 1 | # **Go 实现 web 客户端** 2 | 3 | 在这节,将学习更多关于使用 Go 开发 web 客户端。这个 web 客户端工具的名字是 `webClient.go`,分为四部分展示。 4 | 5 | `webClient.go` 的第一部分包含如下代码: 6 | 7 | ```go 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | "io" 13 | "net/http" 14 | "os" 15 | "path/filepath" 16 | ) 17 | ``` 18 | 19 | `webClient.go` 的第二部分是读取命令行参数获得期望的 URL: 20 | 21 | ```go 22 | func main() { 23 | if len(os.Args) != 2 { 24 | fmt.Printf("Usage: %s URL\n", filepath.Base(os.Args[0])) 25 | return 26 | } 27 | 28 | URL := os.Args[1] 29 | ``` 30 | 31 | `webClient.go` 的第三部分是实际操作发生的地方: 32 | 33 | ```go 34 | data, err := http.Get(URL) 35 | 36 | if err != nil { 37 | fmt.Println(err) 38 | return 39 | ``` 40 | 41 | `http.Get()` 调用做了所有的工作,当您不想要处理参数和选项时它是相当的方便。然而,这样的调用方式在处理过程中没有灵活性。注意,`http.Get()` 返回一个 `http.Response` 变量。 42 | 43 | 余下的代码如下: 44 | 45 | ```go 46 | } else { 47 | defer data.Body.Close() 48 | _, err := io.Copy(os.Stdout, data.Body) 49 | if err != nil { 50 | fmt.Println(err) 51 | return 52 | } 53 | } 54 | } 55 | ``` 56 | 57 | 上面这段代码复制 `http.Response` 结构的 `Body` 字段内容到标准输出。 58 | 59 | 执行 `webClient.go` 将产生如下输出: 60 | 61 | > *只有已小部分展示在这* 62 | 63 | ![](https://github.com/hantmac/Mastering_Go_ZH_CN/tree/master/images/chapter12/12.9.jpg) 64 | 65 | `webClient.go` 的主要问题是几乎不能控制处理过程——您要么获得全部 HTML 输出,要么什么都没有! 66 | 67 | -------------------------------------------------------------------------------- /eBook/chapter13/13.0.md: -------------------------------------------------------------------------------- 1 | # **网络编程 - 构建服务端和客户端** 2 | 3 | 之前的章节讨论了关于网络编程的内容; 包括开发 web 客户端,web 服务端和 web 应用; DNS 查询; 和 HTTP 连接超时。 4 | 5 | 这章将带您更进一步,向您展示怎样编写您自己的 TCP 客户端和服务端,还有 UDP 客户端和服务端。此外,通过俩个例子展示怎样编写一个并发的 TCP 服务端。第一个例子相当简单,并发的 TCP 服务端只返回斐波那契序列数字。而第二个例子将使用[第四章](https://github.com/hantmac/Mastering_Go_ZH_CN/blob/master/eBook/chapter4/04.0.md)(组合类型的使用)的 keyValue.go 应用的代码,在它的基础上,把**key-value 存储**转变为一个并发 TCP 应用,可以在不需要浏览器的情况下操作。 6 | 7 | 在玩转 Go的这一章中,您将了解到如下内容: 8 | 9 | 1. net 标准包 10 | 2. TCP 客户端和服务端 11 | 3. 实现并发 TCP 服务端 12 | 4. UDP 客户端和服务端 13 | 5. 修改 [第八章](https://github.com/hantmac/Mastering_Go_ZH_CN/blob/master/eBook/chapter8/08.0.md)的 kvSaveLoad.go,告诉一个 *Unix 系统* 做什么,才能通过 TCP 连接提供请求 14 | 6. RCP 客户端和服务端 -------------------------------------------------------------------------------- /eBook/chapter13/13.1.md: -------------------------------------------------------------------------------- 1 | # **Go 标准库-net** 2 | 3 | 在 Go 语言中,您不使用 net 包提供的功能是无法创建一个 TCP 或 UDP 的客户端或服务器的。 4 | 5 | net.Dial() 方法作为客户端连接网络,而 net.Listen() 方法作为服务端告诉 Go 程序接收网络连接。这俩个方法只有第一个参数相同,都是网络类型。net.Dial() 和 net.Listen() 方法的返回值,是实现了 io.Reader 和 io.Writer 接口的 net.Conn 类型。 -------------------------------------------------------------------------------- /eBook/chapter13/13.10.md: -------------------------------------------------------------------------------- 1 | # **延展阅读** 2 | 3 | 查看以下资源: 4 | 5 | + 访问 Go 标准库 `net` 文档,在 `https://golang.org/pkg/net` 可以找到。这是 Go 文档中最大的文档之一。 6 | + 尽管这本书谈到了 **RPC**,但没谈到 **gRPC**,这个开源的,高性能的 RPC 框架。用 Go 语言实现的 gRPC 包在 `https://github.com/grpc/grpc-go`。 7 | + IPv4的 ICMP 协议定义在 RFC 792。它可以在很多地方找到,包括 `https://tools.ietf.org/html/rfc792`。 8 | + **WebSocket** 是客户端和远程主机间双向通信的协议。一个 Go 实现的 WebSocket 在 `https://github.com/gorilla/websocket`。您可以在 `http://www.rfc-editor.org/rfc/rfc6455.txt` 学到更多关于 WebSocket。 9 | + 如果您真对网络编程感兴趣并想使用 RAW TCP 数据包,您可以在`https://github.com/google/gopacket` 找到有趣并有帮助的信息和工具。 10 | + 在 `https://github.com/mdlayher/raw` 的 `raw` 包可以让您在网络设备的设备驱动级别读写数据。 11 | -------------------------------------------------------------------------------- /eBook/chapter13/13.11.md: -------------------------------------------------------------------------------- 1 | # **练习** 2 | 3 | + 用 Go 开发一个 **FTP 客户端** 4 | + 接下来用 Go 开发一个 FTP 服务器。实现 FTP 客户端 和 FTP 服务器哪个更困难?为什么? 5 | + 试着实现一个 Go 版本的 `nc(1)` 工具。编写如此复杂工具的秘诀是在实现所有可能选项前,先从实现一个原工具的基础功能版本开始。 6 | + 修改 `TCPserver.go`,使其返回一个网络包中的数据和另一个网络包中的时间 7 | + 修改 `TCPserver.go`,使其可以按顺序为多个客户机提供服务。注意,这和同时服务多个请求不同。简单讲,使用 `for` 循环,以便可以多次执行`Accept()` 调用。 8 | + TCP 服务器,如 `fiboTCP.go`,在接收到给定的信号时往往会终止,因此在 `fiboTCP.go` 中添加信号处理代码,如[第8章](https://github.com/hantmac/Mastering_Go_ZH_CN/tree/master/eBook/chapter8/08.0.md)所述,告诉UNIX系统该怎么做。 9 | + 使用 Go 中普通的 TCP 代替 `http.ListenAndServe()` 函数,开发一个您自己的小型 web server。 -------------------------------------------------------------------------------- /eBook/chapter13/13.12.md: -------------------------------------------------------------------------------- 1 | # **本章小结** 2 | 3 | 这章解决了很多有趣的事情,包括开发 UDP 和 TCP 客户端和服务器,它们是工作在 TCP/IP 计算机网络之上的应用。 4 | 5 | 这是这本书最后一章,我向您表示祝贺并为您选择这本书表示感谢。我希望您能觉得它有用并在您的 Go 之旅中把它作为参考继续使用。 6 | 7 | *Soli Deo gloria* -------------------------------------------------------------------------------- /eBook/chapter13/13.7.md: -------------------------------------------------------------------------------- 1 | # **远程调用(RPC)** 2 | 3 | **远程调用(RPC)**是一种使用 TCP/IP 的进程间通信的 客户端-服务器机制。 RPC 客户端和 RPC 服务器都使用下面这个命名为 `sharedRPC.go` 的包开发。 4 | 5 | ```go 6 | package sharedRPC 7 | 8 | type MyFloats struct { 9 | A1, A2 float64 10 | } 11 | 12 | type MyInterface interface { 13 | Multiply(arguments *MyFloats, reply *float64) error 14 | Power(arguments *MyFloats, reply *float64) error 15 | } 16 | ``` 17 | 18 | `sharedRPC` 包定义了一个名为 `MyInterface` 的接口和一个名为 `MyFloats` 的结构,客户端和服务器都将会使用到。然后,只有 RPC 服务器需要实现这个接口。 19 | 20 | 之后,您需要执行如下命令安装 `sharedRPC.go` 包: 21 | 22 | ```shell 23 | $ mkdir -p ~/go/src/sharedRPC 24 | $ cp sharedRPC.go ~/go/src/sharedRPC/ 25 | $ go install sharedRPC 26 | ``` -------------------------------------------------------------------------------- /eBook/chapter13/13.9.md: -------------------------------------------------------------------------------- 1 | # **接下来的任务** 2 | 3 | 从哲学上讲,没有一本编程书是完美的,这本也不例外!我有没谈及到的 Go 主题吗?当然有!为什么呢?因为一本书中总有更多的主题要涉及,所以如果我试图涵盖所有的主题,那么这本书就永远不会出版!这种情况在某种程度上类似于一个程序的规范——你可以随时添加新的、令人兴奋的特性,但是如果你不冻结它的具体特性,这个程序将永远处于开发阶段,它将永远无法为你的目标观众做好准备。我留下的一些 Go 主题可能会出现在这本书的第二版! 4 | 5 | 读完这本书后,好处是您可以自学了,您能从任何一本好的计算机编程书中获取最大的好处。这本书的主要目的是帮您学习怎么用 Go 语言编程,并获得一些相关经验。然而,没有什么可以代替您自己去探索,并且失败往往成为学习一门编程语言的唯一方式,因此您必须持续不断的拓展一些不同寻常的知识。 6 | 7 | 对于我来说,这是另一本 Go 语言书的结束,但对您是一段旅程的开始!感谢您购买本书,现在准备开始用 Go 编写您自己的软件并学习新知识吧! 8 | 9 | -------------------------------------------------------------------------------- /eBook/chapter2/02.1.md: -------------------------------------------------------------------------------- 1 | ### 认识GO的内部机制 2 | 3 | 在前面章节中提到的所有的Go特性都非常简便,你会一直使用它们。然而,更有价值的事情是看到并理解Go程序背后的运行机制。 4 | 5 | 本章将会介绍垃圾回收以及它的运行机制、如何在Go程序中调用C的代码。在某些情况下在Go中使用C代码是必不可缺的,但是在大多数情况下你并不会用到,因为Go本身就是一种非常强大的编程语言。同样的,如何在C程序中调用Go代码也将会介绍。最后将谈谈如何使用```panic()、recover()```函数和```defer```关键字。 6 | 7 | 本章你将会学习的主题: 8 | 9 | - Go编译器 10 | - Go的垃圾回收是如何工作的 11 | - 如何检测垃圾回收的运转情况 12 | - 在Go中调用C 13 | - 在C中调用Go 14 | - ```panic()``` 和 ```recover()```函数 15 | - ```unsafe```包 16 | - 方便但又棘手的关键字```defer``` 17 | - Linux工具```strace``` 18 | - ```FreeBSD``` 和 ```macOS High Sierra```常用的```dtrace```工具 19 | - 查找Go环境的信息 20 | - 节点树 21 | - Go汇编 -------------------------------------------------------------------------------- /eBook/chapter2/02.2.md: -------------------------------------------------------------------------------- 1 | ### Go 编译器 2 | 3 | Go编译器需要在```go tool```的帮助下执行。```go tool```除了生成可执行文件之外还有很多其他功能。 4 | 5 | 本章节中使用的```unsafe.go```文件不包含任何特殊代码-所提供的命令将适用于每个有效的Go源文件。接下来你将会看到```unsafe.go```的内容。 6 | 7 | 如果你使用```go tool compile```命令编译```unsafe.go```文件,会得到一个扩展名为```.o```的目标文件。下面的展示这个命令在macOS操作系统中执行的结果: 8 | 9 | > ```shell 10 | > $ go tool compile unsafe.go 11 | > $ ls -l unsafe.o 12 | > -rw-r--r-- 1 mstouk staff 5495 Oct 30 19:51 unsafe.o 13 | > $ file unsafe.o 14 | > unsafe.o: data 15 | > ``` 16 | 17 | 目标文件是包含了目标代码的二进制文件,它以可重定位格式的形式展现,很多时候不能被直接执行。可重定位格式的最大好处是在链接阶段它需要尽可能少的内存。 18 | 19 | 如果执行```go tool compile -pack```命令,将会得到一个压缩文件。 20 | 21 | > ``` 22 | > $ go tool compile -pack unsafe.go 23 | > $ ls -l unsafe.a 24 | > -rw-r--r-- 1 mtsouk staff 5680 Oct 30 19:52 unsafe.a 25 | > $ file unsafe.a 26 | > unsafe.a: current ar archive 27 | > ``` 28 | 29 | 压缩文件也是一个二进制文件,但是它包含了一个或者多个文件,主要的目的是把多个文件组织到单个文件中。Go使用的压缩文件被称为```ar```。 30 | 31 | 使用下面的命令可以列出```.a```压缩文件的内容: 32 | 33 | > ``` 34 | > $ ar t unsafe.a 35 | > __.PKGDEF 36 | > _go_.o 37 | > ``` 38 | 39 | ```go tool compile```的另一个真正有价值的命令行标志是```-race```,它允许您检测竞态条件。在第十章中你会学到更多关于竞态条件以及为什么要避免竞态条件的知识点。 40 | 41 | 本章的最后讨论汇编语言和节点树的时候,你还会学到 一个同样有用的```go tool compile```命令。现在为了撩动你,尝试一下下面的命令吧: 42 | 43 | > ``` $ go tool compile -S unsafe.go``` 44 | 45 | 你可能发现,以上命令的输出会让你难以理解,这正说明了Go可以很好地帮你隐藏不必要的复杂性,除非你要求Go展示出来。 -------------------------------------------------------------------------------- /eBook/chapter2/02.3.2.md: -------------------------------------------------------------------------------- 1 | ### 垃圾回收器背后的更多操作 2 | 3 | 这一小节会深入探索go垃圾回收器。 4 | 5 | go垃圾回收器的主要关注点是低延迟,也就是说为了进行实时操作它会有短暂的暂停。另一方面,创建新对象然后使用指针操作存活对象是程序始终在做的事情,这个过程可能最终会创建出不会再被访问到的对象,因为没有指向那些对象的指针。这种对象即为垃圾对象,它们等待被垃圾回收器清理然后释放它们的空间。之后它们释放的空间可以再次被使用。 6 | 7 | 8 | 垃圾回收中使用的最简单的算法就是经典的**标记清除算法(mark-and-sweep)**:算法为了遍历和标记堆中所有可触达对象,会把程序停下来(**stop the world**)。之后,它会去清扫(sweeps)不可触达的对象。在算法的标记(mark)阶段,每个对象被标记为白色、灰色或黑色。灰色的子对象标记为灰色,而原始的对象此时会标记为黑色。没有更多灰色对象去检查的话就会开始清扫阶段。这个技术适用是因为没有从黑色指向白色的指针,这是算法的基本不变要素。 9 | 10 | 11 | 尽管标记清除算法很简单,但是它会暂停程序的运行,这意味着实际过程中它会增加延迟。go会通过把垃圾回收器作为一个并发的处理过程,同时使用前一节讲的三色算法,来降低这种延迟。但是,在垃圾回收器并发运行时候,其它的过程可能会移动指针或者创建对象,这会让垃圾回收器处理非常困难。所以,让三色算法并发运行的关键点就是,维持标记清除算法的不变要素即没有黑色的对象能够指向白色集合对象。 12 | 13 | 14 | 因此,新对象必须进入到灰色集合,因为这种方式下标记清除的不变要素不会被改变。另外,当程序的一个指针移动,要把指针所指的对象标记为灰色。你可以说灰色集合是白色集合和黑色集合中间的“屏障”。最后,每次一个指针移动,会自动执行一些代码,也就是我们之前提到的**写屏障**,它会去进行重新标色。 15 | 16 | 为了能够并发运行垃圾回收器,写屏障代码产生的延迟是必要的代价。 17 | 18 | 注意**Java**程序语言有许多垃圾回收器,它们在各种参数下能够进行高度配置。其中一种垃圾回收器叫G1,推荐在低延迟应用的程序使用它。 19 | 20 | ###### *一定要记住,Go垃圾回收器是一个实时的垃圾回收器 ,它是和其他goroutines一起并发运行的* 21 | 22 | 23 | 在[第11章](https://github.com/hantmac/Mastering_Go_ZH_CN/blob/master/eBook/chapter11/11.0.md),代码测试,优化以及分析,你会学习到如何能够用图表的方式呈现程序的性能。这一章节也会包括一些关于Go垃圾回收器操作的一些信息。 24 | 25 | 26 | 下一节会介绍**不安全代码(unsafe code)和```unsafe```的go标准库 -------------------------------------------------------------------------------- /eBook/chapter2/02.3.3.md: -------------------------------------------------------------------------------- 1 | ### Unsafe code 2 | 3 | **Unsafe code**是一种绕过go类型安全和内存安全检查的Go代码。大多数情况,unsafe code是和指针相关的。但是要记住使用unsafe code有可能会损害你的程序,所以,如果你不完全确定是否需要用到unsafe code就不要使用它。 4 | 5 | 以下面的```unsafe.go```为例,看一下unsafe code的使用 6 | 7 | ``` 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | "unsafe" 13 | ) 14 | 15 | func main() { 16 | var value int64 = 5 17 | var p1 = &value 18 | var p2 = (*int32)(unsafe.Pointer(p1)) 19 | ``` 20 | 这里使用了```unsafe.Pointer()```方法,这个方法能让你创造一个```int32```的```p2```指针去指向一个```int64```的```value```变量,而这个变量是使用```p1```指针去访问的,注意这种做法是有风险的。 21 | 22 | 任何go指针都可以转化为```unsafe.Pointer```指针。 23 | 24 | ###### *```unsafe.Pointer```类型的指针可以覆盖掉go的系统类型。这毫无疑问很快,但是如果不小心或者不正确使用的话就会很危险,它给了开发者更多选择去掌控数据。* 25 | 26 | ```unsafe.go```后面部分如下 27 | 28 | ``` 29 | fmt.Println("*p1: ", *p1) 30 | fmt.Println("*p2: ", *p2) 31 | *p1 = 5434123412312431212 32 | fmt.Println(value) 33 | fmt.Println("*p2: ", *p2) 34 | *p1 = 54341234 35 | fmt.Println(value) 36 | fmt.Println("*p2: ", *p2) 37 | } 38 | ``` 39 | ###### *你可以使用一个星号(***)来解引用一个指针* 40 | 41 | 运行```unsafe.go```,会得到如下的输出 42 | 43 | ``` 44 | *p1: 5 45 | *p2: 5 46 | 5434123412312431212 47 | *p2: -930866580 48 | 54341234 49 | *p2: 54341234 50 | ``` 51 | 52 | 那么这个输出说明了什么呢?它告诉了我们,使用32-bit的指针无法存一个64-bit的整数型 53 | 54 | 下一节你会看到,使用```unsafe```库中的方法可以做许多有趣的事情 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /eBook/chapter2/02.3.4.md: -------------------------------------------------------------------------------- 1 | ### 关于unsafe包 2 | 3 | 你已经实际操作过```unsafe```包的东西了,现在来看一下为什么这个库这么特别。 4 | 5 | 6 | 7 | 首先,如果你看了```unsafe```包的源码,你可能会感到惊讶。在macOS Hight Sierra系统上,可以使用**Homebrew**安装1.9.1版本的Go 。```unsafe```源码路径在```/usr/local/Cellar/go/1.9.1/libexec/src/unsafe/unsafe.go```下面,不包含注释,它的内容如下 8 | 9 | ``` 10 | 11 | $ cd /usr/local/Cellar/go/1.9.1/libexec/src/unsafe/ 12 | $ grep -v '^//' unsafe.go|grep -v '^$' 13 | package unsafe 14 | type ArbitraryType int 15 | type Pointer *ArbitraryType 16 | func Sizeof(x ArbitraryType) uintptr 17 | func Offsetof(x ArbitraryType) uintptr 18 | func Alignof(x ArbitraryType) uintptr 19 | ``` 20 | 21 | OK,其它的```unsafe```包的go代码去哪里了?答案很简单:当你import到你程序里的时候,Go编译器实现了这个unsafe库。 22 | 23 | ###### *许多系统库,例如```runtime```,```syscall```和```os```会经常使用到```usafe```库* 24 | -------------------------------------------------------------------------------- /eBook/chapter2/02.5.1.md: -------------------------------------------------------------------------------- 1 | ### Go Package 2 | 3 | 本节将展示C示例程序用到的```Go package```代码。```Go package```的名字必须是```main```,但是文件名可以随意,我们的例子中,文件名是```usedByC.go```,分三部分展示。 4 | 5 | *你可能不了解```Go package```机制,在第六章会详细的介绍。* 6 | 7 | 第一部分的```Go package```代码: 8 | 9 | > ```go 10 | > package main 11 | > 12 | > import "C" 13 | > 14 | > import ( 15 | > "fmt" 16 | > ) 17 | > ``` 18 | 19 | 前面提到,```Go package```的名字必须是```main```,同样的也需要导入```"C" package```。 20 | 21 | 第二部分的代码如下: 22 | 23 | > ```go 24 | > //export PrintMessage 25 | > func PrintMessage() { 26 | > fmt.Println("A Go function!") 27 | > } 28 | > ``` 29 | 30 | 如果一个Go函数想要被C语言调用,必须要先导出。你应该在函数实现的开始部分,添加一行以```export```开头的注释,```export```后面要加上函数的名字,这样C程序才知道怎么使用。 31 | 32 | 最后一部分的代码: 33 | 34 | > ```go 35 | > //export Multiply 36 | > func Multiply(a, b int) int { 37 | > return a * b 38 | > } 39 | > func main() { 40 | > } 41 | > ``` 42 | 43 | 这个```main()```函数不需要任何的函数体,因为不需要导出给C代码使用,同样的,要导出```Multiply```函数,也需要将```//export Multiply```注释添加到函数实现之前。 44 | 45 | 接着,你需要用Go代码生成一个C共享库,命令如下: 46 | 47 | > ```shell 48 | > $ go build -o usedByC.o -buildmode=c-shared usedByC.go 49 | > ``` 50 | 51 | 上面的命令会产生```usedByC.h```和```usedByC.o```两个文件。 52 | 53 | > ```shell 54 | > $ ls -l usedByC.* 55 | > -rw-r--r--@ 1 mtsouk staff 56 | > 204 57 | > -rw-r--r-- 1 mtsouk staff 58 | > 1365 59 | > -rw-r--r-- 1 mtsouk staff 2329472 60 | > $ file usedByC.o 61 | > usedByC.o: Mach-O 64-bit dynamically 62 | > Oct 31 20:37 usedByC.go 63 | > Oct 31 20:40 usedByC.h 64 | > Oct 31 20:40 usedByC.o 65 | > linked shared library x86_64 66 | > ``` 67 | 68 | **注意**:不要修改```usedByC.h```文件。 -------------------------------------------------------------------------------- /eBook/chapter2/02.5.2.md: -------------------------------------------------------------------------------- 1 | ### C代码 2 | 3 | C代码在```willUseGo.c```文件中,分两部分展示,第一部分如下: 4 | 5 | > ```c 6 | > #include 7 | > #include "usedByC.h" 8 | > int main(int argc, char **argv) { 9 | > GoInt x = 12; 10 | > GoInt y = 23; 11 | > printf("About to call a Go function!\n"); 12 | > PrintMessage(); 13 | > ``` 14 | 15 | 导入```usedByC.h```之后,就可以使用其中实现的函数。 16 | 17 | 第二部分代码: 18 | 19 | > ```c 20 | > GoInt p = Multiply(x,y); 21 | > printf("Product: %d\n",(int)p); 22 | > printf("It worked!\n"); 23 | > return 0; 24 | > } 25 | > ``` 26 | 27 | 变量```GoInt p```是从Go函数中获取一个整数值,使用```(int)p```可以把它转换成C语言的整数。 28 | 29 | 在Mac机器上编译和执行```willUseGo.c```,输出如下: 30 | 31 | > ```shell 32 | > $ gcc -o willUseGo willUseGo.c ./usedByC.o 33 | > $ ./willUseGo 34 | > About to call a Go function! 35 | > A Go function! 36 | > Product: 276 37 | > It worked! 38 | > ``` -------------------------------------------------------------------------------- /eBook/chapter2/02.5.md: -------------------------------------------------------------------------------- 1 | ### C代码中调用Go函数 2 | 3 | 在C中可以调用Go函数,接下来,呈现两个C语言的例子,在这两个例子中,调用了两个Go函数,其中Go package将会被转换成这两个C程序的共享库。 -------------------------------------------------------------------------------- /eBook/chapter3/03.1.1.md: -------------------------------------------------------------------------------- 1 | # **for循环** 2 | for循环是编程中最常见的循环了,它允许你迭代指定次数,或者在for循环开始的时候计算一个初始值然后只要条件满足就一直迭代下去,这些值包括切片、数组、字典等的长度。这意味着使用for循环是获取一个数组、切片或者字典所有元素的最通用的方式。另外一个方式就是使用range关键字。 3 | 4 | 下面的代码展示了一个for循环的最简单的使用方式,让一个变量在一定范围内进行遍历: 5 | 6 | >```go 7 | > for i := 0; i < 100; i++ { 8 | > 9 | > } 10 | > ``` 11 | 12 | 在前面的循环中,i的取值将是从0到99。一旦i达到了100,for循环将终止执行。在这段代码中,i是一个本地的临时变量,这意味着在for循环的执行终止之后,i会在未来某个时刻被垃圾回收从而消失。然而,如果i是在for循环之外定义的,那它将在for循环之后继续存在,并且它的值将是100。 13 | 14 | 你可以使用break关键字来退出for循环。break关键字同时也允许你创建一个没有像i < 100的这样的终止条件的for循环,因为终止条件可以放在for循环内部的代码块中。在for循环中允许有多个退出循环的地方。 15 | 16 | 此外,你可以使用continue关键字在for循环中跳过一次循环。continue关键字会停止执行当前的代码块,跳回顶部的for循环,然后继续进行下一次循环。 -------------------------------------------------------------------------------- /eBook/chapter3/03.1.2.md: -------------------------------------------------------------------------------- 1 | # **while 循环** 2 | 正如先前提到的,Go没有提供while关键字来进行while循环的编写,但是它允许你使用for循环来替代while循环。这一节将用两个例子来展示for循环是怎么替代while循环的工作的。 3 | 4 | 下面是一个典型的你会写while(condition)的例子: 5 | 6 | >```go 7 | >for { 8 | > 9 | >} 10 | >``` 11 | 12 | 注意此时开发者需要使用break关键字来退出这个for循环! 13 | 14 | 此外,for循环还能模拟一个在其他编程语言中会出现的do...while循环。下面的代码给了一个Go语言中等价于do...while(anExpression)的操作: 15 | 16 | >```go 17 | >for ok:=true; ok; ok = anExpression { 18 | > 19 | >} 20 | >``` 21 | 22 | 一旦变量ok的值是false,则for循环终止执行。 -------------------------------------------------------------------------------- /eBook/chapter3/03.1.3.md: -------------------------------------------------------------------------------- 1 | # **range关键字** 2 | Go同时提供了range关键字,它能配合for循环以帮助你在遍历Go的数据类型时写出更易于理解的代码。 3 | 4 | range关键字的主要优势在于并不需要知道一个切片或者字典的长度就可以一个接一个的对它们的元素进行操作。稍后你会看到range的示例。 -------------------------------------------------------------------------------- /eBook/chapter3/03.1.md: -------------------------------------------------------------------------------- 1 | # **Go循环** 2 | 每个编程语言都有一种进行循环的方式,Go也不例外。Go提供了for循环,用来对多种数据类型进行遍历。 3 | 4 | > Go没有提供while关键字。但是,Go的for循环语句完全可以替代while循环。 5 | 6 | -------------------------------------------------------------------------------- /eBook/chapter3/03.10.md: -------------------------------------------------------------------------------- 1 | # **本章小结** 2 | 3 | 本章你学习了很多有趣的Go知识,包括映射(map)、数组、切片、指针、常量、循环以及Go处理时间与日期的技巧。学到现在,你应该能够理解为什么切片要优于数组。 4 | 5 | 下一章将介绍构建与使用组合类型的知识,主要是使用`struct`关键字创建的结构体,之后会讨论`string`变量和**元组**。 6 | 7 | 另外,下一章还会涉及到正则表达式和模式匹配,这是一个比较tricky的主题,不仅针对Go,对其他所有语言都是一样的,合理地使用正则表达式能够大大简化你的工作,是非常值得学习一下的。 8 | 9 | 你还会了解关于`switch`关键字的知识,以及使用`strings`包处理**UTF-8**字符串的技巧。 10 | 11 | -------------------------------------------------------------------------------- /eBook/chapter3/03.3.3.md: -------------------------------------------------------------------------------- 1 | # **字节切片** 2 | 3 | 类型为byte的切片成为字节切片,可通过下面的代码创建一个字节切片: 4 | 5 | > s := make([]byte,5) 6 | 7 | 字节切片的操作与其他类型的切片并没有什么区别,但是在输入输出中(网络,文件流等)使用的非常多,你将在`第八章`大量使用字节切片。 -------------------------------------------------------------------------------- /eBook/chapter3/03.3.5.md: -------------------------------------------------------------------------------- 1 | # **多维切片** 2 | 3 | 跟数组一样,切片同样可以是多维的,下面代码创建一个二维切片: 4 | 5 | > s1 := make([][]int, 4) 6 | 7 | > 如果你发现你的代码中出现很多多维切片,你就要考虑你的代码设计是否合理并且使用不需要多维切片的更简单的设计。 8 | 9 | 下一小结中你会看到一段使用多维切片的代码示例。 10 | 11 | -------------------------------------------------------------------------------- /eBook/chapter3/03.3.md: -------------------------------------------------------------------------------- 1 | # **Go 切片** 2 | 3 | Go的切片十分强大,可以毫不夸张地说切片完全能够取代数组。只有非常少的情况下,你才需要创建数组而非切片,最常见的场景就是你非常确定你所存储的元素数量。 4 | 5 | > 切片的底层是数组,这意味着Go为每一个切片创建一个底层数组 6 | 7 | 切片作为函数的形参时是传引用操作,传递的是指向切片的内存地址,这意味着在函数中对切片的任何操作都会在函数结束后体现出来。另外,函数中传递切片要比传递同样元素数量的数组高效,因为Go只是传递指向切片的内存地址,而非拷贝整个切片。 -------------------------------------------------------------------------------- /eBook/chapter3/03.4.1.md: -------------------------------------------------------------------------------- 1 | # **Map值为nil的坑** 2 | 3 | 下面的代码会正常工作: 4 | 5 | > aMap := map[string]int{} 6 | > 7 | > aMap["test"] = 1 8 | 9 | 然而下面的代码是不能工作的,因为你将`nil`赋值给map: 10 | 11 | > aMap := map[string]int{} 12 | > 13 | > aMap = nil 14 | > 15 | > fmt.Println(aMap) 16 | > 17 | > aMap["test"] = 1 18 | 19 | 将以上代码保存至`failMap.go`,执行后会产生下面的错误信息(事实上,如果你用IDE编程,IDE就会提醒你有错误): 20 | 21 | > $ go run failMap.go 22 | > 23 | > map[] 24 | > 25 | > panic: assignment to entry in nil map 26 | -------------------------------------------------------------------------------- /eBook/chapter3/03.4.2.md: -------------------------------------------------------------------------------- 1 | # **何时该使用Map?** 2 | 3 | 与切片与数组相比,map(映射)的功能要强大的多,但是具有灵活性的同时也伴随着性能损耗,实现Go map往往需要更多的处理能力。但是不用担心,Go的内置数据结构是非常高效的,所以当你需要map的时候就尽情地去用吧! 4 | 5 | 你应该记住的是Go map是非常方便的而且能存储多种不同的数据类型,同时其用法易于理解且上手迅速。 -------------------------------------------------------------------------------- /eBook/chapter3/03.5.md: -------------------------------------------------------------------------------- 1 | # **Go 常量** 2 | 3 | 常量是的值是不能改变的,Go使用关键字`const`定义常量。 4 | 5 | > 通常来说,常量是全局变量。因此,当你的代码中出现大量在局部定义的常量时,你就应该考虑重新设计你的代码了。 6 | 7 | 显而易见,使用常量的好处就是保证了该值不会在程序运行过程中被修改! 8 | 9 | 严格来说,常量的值在编译期间就被确定了。在这种情况下,Go可以使用布尔类型、字符串、或者数字类型存储常量的值。 10 | 11 | 你可以使用下面的代码定义常量: 12 | 13 | > const HEIGHT = 200 14 | 15 | 另外,你还可以一次性定义多个常量: 16 | 17 | > const ( 18 | > 19 | > C1 = "C1C1C1" 20 | > 21 | > C2 = "C2C2C2" 22 | > 23 | > C3 = "C3C3C3" 24 | > 25 | > ) 26 | 27 | 下面这三种声明变量的方式在Go看来是一样的: 28 | 29 | > s1 := "My String" 30 | > 31 | > var s2 = "My String" 32 | > 33 | > var s3 string = "My String" 34 | 35 | 以上三个变量的声明并没有使用`const`关键字,所以它们并不是常量。这并不意味着你不能使用相似的方式定义两个常量: 36 | 37 | > const s1 = "My String" 38 | > 39 | > const s2 string = "My String" 40 | 41 | 尽管`s1`和`s2`都是常量,但是`s2`定义时声明了其类型,意味着它比常量`s1`的定义更加严格。这是因为一个声明类型的Go常量必须遵循与声明过类型的变量相同的严格规则,换句话说,未声明类型的常量无需遵循严格规则,使用起来会更加自由。但是,即使在定义常量时没有声明其类型,Go会根据其值判断其类型,因为你不想在使用该常量时考虑所有的规则。下面我们将用一个简单的例子来说明,当你为常量赋予具体类型时会遇到哪些问题: 42 | 43 | > const s1 = 123 44 | > 45 | > const s2 float64 = 123 46 | > 47 | > var v1 float32 = s1*12 48 | > 49 | > var v2 float32 = s2*12 50 | 51 | 编译器正常通过`v1`的声明及初始化,但是由于`s2`和`v2`的类型不同,编译器就会报错: 52 | 53 | > $ go run a.go 54 | > 55 | > $ command-line-argument 56 | > 57 | > ./a.go:12:6: canot use s2 * 12 (type float64) as type float32 in assignment 58 | 59 | > 代码建议:如果你要用到许多常量,最好将它们定义到同一个包中。 60 | 61 | -------------------------------------------------------------------------------- /eBook/chapter3/03.7.1.md: -------------------------------------------------------------------------------- 1 | # **解析时间** 2 | 3 | 将时间类型的变量转换成其他格式的时间与日期是非常简单的,但是当你想要将`string`类型转换成时间类型,以检查其是否是一个有效的时间格式时,就会比较麻烦。`time`包提供了`time.parse()`函数帮助你解析时间与日期字符串,将其转换成`time`类型。`time.Parse()`接收两个参数,第一个参数是你期望得到的时间格式,第二个参数是你要解析的时间字符串。第一个参数是Go与时间解析相关的一系列常量。 4 | 5 | > 这些常量可以用来创建你期望的时间日期格式,具体介绍见`https://golang.org./src/time/format.go`。Go并没有定义一些时间格式像`DDYYMM`、`%D%Y%M`等,最开始你可能会觉得Go的这种处理方式很蠢,但是用多了后你肯定会喜欢上这种简洁的方式。 6 | 7 | 这些与时间处理相关的常量分别是,`15`代表解析小时,`04`代表解析分钟,`05`解析秒,同时你可以使用`PM`将字符串中的字母转为大写,`pm`转为小写。 8 | 9 | > 开发者只需要将上面的常量按照字符串中日期的顺序排放就可以了。 10 | 11 | 其实你可以将`time.Parse()`的第一个参数看做正则表达式。 -------------------------------------------------------------------------------- /eBook/chapter3/03.7.3.md: -------------------------------------------------------------------------------- 1 | # **解析日期** 2 | 3 | 在本节中你将学习如何将字符串转为日期,同样是使用`time.Parse()`。 4 | 5 | Go解析日期的常量是:`Jan`用来解析月份(英文月份简写),`2006`用来解析年,`02`用来解析天,`Mon`用来解析周几(如果是`Monday`,那就是周几的英文全称),同样如果你使用`January`而不是`Jan`,你将会得到月份的英文全称而不是三个字母的简写。 -------------------------------------------------------------------------------- /eBook/chapter3/03.7.4.md: -------------------------------------------------------------------------------- 1 | # **解析日期的代码示例** 2 | 3 | 本节的代码`parseDate.go`,分两部分讲解。 4 | 5 | 第一部分: 6 | 7 | > ```go 8 | > package main 9 | > 10 | > import ( 11 | > "fmt" 12 | > "os" 13 | > "path/filepath" 14 | > "time" 15 | > ) 16 | > 17 | > func main() { 18 | > var myDate string 19 | > 20 | > if len(os.Args) != 2 { 21 | > fmt.Printf("Usage: %s date\n", 22 | > filepath.Base(os.Args[0])) 23 | > os.Exit(0) 24 | > } 25 | > 26 | > myDate = os.Args[1] 27 | > ``` 28 | 29 | 第二部分: 30 | 31 | > ```go 32 | > d,err := time.Parse("02 January 2006",myDate) 33 | > if err == nil { 34 | > fmt.Println("Full",d) 35 | > fmt.Println("Time", d.Day(), d.Month(), d.Year()) 36 | > } else { 37 | > fmt.Println(err) 38 | > } 39 | > } 40 | > ``` 41 | 42 | 如果你想要在月份和年之间加入"-",只需要将格式“02 January 2006“改成“02 January-2006”即可。 43 | 44 | 执行`parseDate.go`你将得到下面的输出: 45 | 46 | > $ go run parseDate.go 47 | > 48 | > usage: parseDate string 49 | > 50 | > $ go run parseDate.go "12 January 2019" 51 | > 52 | > Full 2019-01-12 00:00:00 +0000 UTC 53 | > Time 12 January 2019 54 | 55 | -------------------------------------------------------------------------------- /eBook/chapter3/03.8.md: -------------------------------------------------------------------------------- 1 | # **延展阅读** 2 | 3 | 可以阅读下面的资源: 4 | 5 | - 阅读官方的`time`包:https://golang.org/pkg/time 6 | - 官方讲解正则表达式的包`regexp`:https://golang.org/pkg/regexp 7 | 8 | -------------------------------------------------------------------------------- /eBook/chapter3/03.9.md: -------------------------------------------------------------------------------- 1 | # **练习** 2 | 3 | - 使用iota编写常量生成器表示数字0-4 4 | - 使用iota编写常量生成器表示一周的天数 5 | - 编写程序将数组转为map 6 | - 自己动手编写parseTime.go,不要忘记写测试 7 | - 编写timeDate.go使其能够处理两种格式的时间与日期 8 | - 自己动手编写parseDate.go -------------------------------------------------------------------------------- /eBook/chapter4/04.0.md: -------------------------------------------------------------------------------- 1 | # **组合类型的使用** 2 | 3 | 上一章我们讨论了数组、切片、映射、指针、常量、`for`循环、`range`关键字的使用,以及处理始建于日期的技巧。这一章我们将探索更加高级的Go特性,比如元组和字符串,标准库`strings`,`switch`语句,以及使用`struct`关键字创建结构体。另外一部分比较重要的内容使用Go实现正则表达式以及模式匹配。完成上面的章节后,我们将实现一个简单的K-V存储。 4 | 5 | 下面是本章的内容概览: 6 | 7 | - Go结构体和`struct`关键字 8 | - Go元组 9 | - Go 字符串,runes,字节切片,以及字符串字面量 10 | - Go的正则表达式 11 | - Go的模式匹配 12 | - `switch`语句 13 | - 关于标准库`strings`的使用 14 | - 计算高精度的**PI**值 15 | - 实现一个**K-V存储** 16 | 17 | -------------------------------------------------------------------------------- /eBook/chapter4/04.1.md: -------------------------------------------------------------------------------- 1 | # **关于组合类型** 2 | 3 | 尽管Go提供的类型是非常方便,快速和灵活的,但是不可能满足开发者所有的需求。Go通过提供结构体来解决此问题,开发者可以实现自定义类型。另外,Go还支持元组操作,意思是允许函数返回多个值,这些值并不需要提前声明结构体存放。 -------------------------------------------------------------------------------- /eBook/chapter4/04.10.md: -------------------------------------------------------------------------------- 1 | # **练习** 2 | 3 | - 写一个Go程序,识别无效的IPv4地址 4 | - 说说`make`和`new`的区别 5 | - 说说字符、字节和`rune`之间的区别 6 | - 在不使用UNIX工具的前提下,修改`findIPv4.go`使之能够打印出出现次数最多的IPv4地址 7 | - 写一个Go程序,能够识别出log文件中产生404错误的IPv4地址 8 | - 使用`math/big`包计算高精度平方根,算法自选 9 | - 写一个Go程序,从给定时间与日期中寻找特定格式的时间。 10 | - 写一个正则表达式匹配200-400之间的整数 11 | - 为`keyValue.go`添加日志打印 12 | - 修改`findIPv4.go`中的`findIP()`函数,保证`findIp()`多次调用时正则表达式只编译一次 -------------------------------------------------------------------------------- /eBook/chapter4/04.11.md: -------------------------------------------------------------------------------- 1 | # **本章小结** 2 | 3 | 在本章中,你学到了Go的很多实用特性,包括创建与使用结构体,元组,字符串,runes以及Unicode标准库。另外,你也掌握了模式匹配与正则表达式,`switch`语句,`strings`标准库;并且,你实现了Go版本的K-V存储,使用`math/big`包计算出高精度的Pi值。 4 | 5 | 在下一章中,你将学习使用更加高级的数据结构来操作数据,比如二叉树,链表,双向链表,队列,栈,哈希表以及`container`标准库中的数据结构。下一章最后的主题将是**随机数**,我们将生成难以破解的密码字符串。 -------------------------------------------------------------------------------- /eBook/chapter4/04.2.2.md: -------------------------------------------------------------------------------- 1 | # **使用new关键字** 2 | 3 | Go支持使用`new`关键创建新的对象,必须要注意的是,这种方式返回的对象的指针! 4 | 5 | 你可以创建一个`aStructure`类型的变量: 6 | 7 | > pS := new(aStructure) 8 | 9 | 执行上述代码后,你得到的是值为`nil`的对象,并没有初始化。 10 | 11 | > `new`和`make`最大的区别就是:`new`返回的是空的内存地址,即没有做初始化。另外,`make`仅可以用来创建映射,切片和通道,而且并不是返回指针。 12 | 13 | 下面的代码将会创建一个指向切片的指针,并且值为`nil`: 14 | 15 | > sP := new([]aStructure) 16 | 17 | -------------------------------------------------------------------------------- /eBook/chapter4/04.3.md: -------------------------------------------------------------------------------- 1 | # **元组** 2 | 3 | 严格来讲,**元组**是由多个部分组成的有序列表,最重要的是Go本身不支持元组类型,虽然Go官方并不关心元组,但实际上它提供了元组的某些操作。 4 | 5 | 有趣的是我们在第一章已经接触过Go的元组操作,像下面的这种操作,使用一条语句获取两个返回值: 6 | 7 | > min,_ := strconv.ParseFloat(arguments[1], 64) 8 | 9 | `tuples.go`中的代码将会分成三部分来解释Go的元组,请注意下面代码中的函数将返回值以元组的形式返回。 10 | 11 | 第一部分: 12 | 13 | > ```go 14 | > package main 15 | > 16 | > import "fmt" 17 | > 18 | > func retThree(x int) (int, int, int) { 19 | > return 2 * x, x*x,-x 20 | > } 21 | > ``` 22 | 23 | `retThree()`函数返回了包含三个整数元素的元组,这种能力使得函数能够返回一组数据,而无需将它们聚合到结构体中或者返回一个结构体变量。 24 | 25 | 在第六章你将会学习到如何给函数的返回值命名,这是一个非常方便的特性。 26 | 27 | 第二部分代码: 28 | 29 | > ```go 30 | > func main() { 31 | > fmt.Println(retThree(10)) 32 | > n1, n2, n3 := retThree(20) 33 | > fmt.Println(n1,n2,n3) 34 | > ``` 35 | 36 | 这里我们使用了两次`retThree()`函数。第一次我没让你将其返回值保存,第二次使用三个变量保存返回值,在Go的术语中这叫做元组赋值,看到这里,你是不是有了一种`Go支持元组!`的错觉。如果有些返回值你并不关心,可以使用`_`操作符忽略掉它们。要知道,在Go的代码里声明了但是未使用的代码是会导致编译错误的。 37 | 38 | 第三部分代码: 39 | 40 | > ```go 41 | > n1, n2 = n2, n1 42 | > fmt.Println(n1, n2, n3) 43 | > 44 | > x1, x2, x3 := n1*2,n1*n1, -n1 45 | > 46 | > fmt.Println(x1,x2,x3) 47 | > } 48 | > ``` 49 | 50 | 可以看到,依靠这种元组操作,我们无需借助`temp`变量就可以实现两个数字的交换。 51 | 52 | 执行`tuples.go`可得到如下输出: 53 | 54 | > $ go run tuples.go 55 | > 56 | > 20 100 -10 57 | > 58 | > 40 400 -20 59 | > 60 | > 400 40 -20 61 | > 62 | > 800 160000 -400 -------------------------------------------------------------------------------- /eBook/chapter4/04.4.1.md: -------------------------------------------------------------------------------- 1 | # **理论知识** 2 | 3 | 每一个正则表达式都通过一种叫做**有限自动机**的状态转换图表,被编译成识别器。一个有限自动机可以使确定性的也可以是不确定性的。不确定性的意思是一种输入可能会产生多种输出状态。识别器是一种程序,它接收一个字符串`x`并且能够分辨出`x`是何种语言写的。 4 | 5 | **语法**能够以一种格式化的语言为字符串生成一系列产生式规则,产生式规则描述了根据词法生成有效字符串的方法。语法器只能描述字符串的结构,不能描述一个字符串的含义或者描述该字符串能在什么上下文中用来做什么。要注意,语法是定义或者使用正则表达式的核心。 6 | 7 | > 尽管正则表达式可以用来解决棘手的问题,但是不要任何问题都使用正则表达式,一定要在正确的地方选择正确的工具! 8 | 9 | 接下来的这一小节将会展示三个正则表达式和模式匹配的例子。 -------------------------------------------------------------------------------- /eBook/chapter4/04.4.md: -------------------------------------------------------------------------------- 1 | # **正则表达式与模式匹配** 2 | 3 | 模式匹配在Go中占有重要的地位,是能够根据正则表达式查询出特定的字符集的技术。模式匹配成功后你就可以提取出你想要的字符串,并对其进行替换、删除等进一步操作。 4 | 5 | Go标准库中已经帮你设计好了用于正则表达式的包-`regexp`,我们将会在下面深入讨论。 6 | 7 | > 当你在代码中使用正则表达式时,定义符合条件的正则表达式是重中之重。 8 | 9 | -------------------------------------------------------------------------------- /eBook/chapter4/04.5.2.md: -------------------------------------------------------------------------------- 1 | # **关于Unicode的包** 2 | 3 | Go提供的`unicode`标准库提供了很多便捷的函数,其中`unicode.IsPrint()`能帮助你判断字符串的某一部分是否能够以rune的类型打印出来。接下来将会在代码`unicode.go`中分两部分展示该函数的用法。 4 | 5 | 第一部分: 6 | 7 | > ```go 8 | > package main 9 | > 10 | > import ( 11 | > "fmt" 12 | > "unicode" 13 | > ) 14 | > 15 | > func main() { 16 | > const sL= "\x99\x00ab\x50\x00\x23\x50\x29\x9c" 17 | > ``` 18 | 19 | 第二部分: 20 | 21 | > ```go 22 | > for i := 0; i < len(sL); i++ { 23 | > if unicode.IsPrint(rune(sL[i])) { 24 | > fmt.Printf("%c\n", sL[i]) 25 | > } else { 26 | > fmt.Println("Not printable!") 27 | > } 28 | > } 29 | > } 30 | > ``` 31 | 32 | `unicode.IsPrint()`函数将检查字符串`sL`的每个元素是否是rune类型,如果是的话将返回`true`否则返回false。如果你需要更多操作Unicode字符的方法,可以参考官方`unicode`包的介绍。 33 | 34 | 执行`unicode.go`将会打印: 35 | 36 | > $ go run unicode.go 37 | > 38 | > ```shell 39 | > Not printable! 40 | > Not printable! 41 | > a 42 | > b 43 | > P 44 | > Not printable! 45 | > # 46 | > P 47 | > ) 48 | > Not printable! 49 | > ``` 50 | 51 | -------------------------------------------------------------------------------- /eBook/chapter4/04.9.md: -------------------------------------------------------------------------------- 1 | # **延展阅读** 2 | 3 | - `regexp`标准库的详细讲解-https://golang.org/pkg/regexp 4 | - 阅读`grep`工具的使用说明 5 | - 使用Go开发一个程序,能够找出log文件中所有的IPv4地址 6 | - 关于`math/big`包的详细讲解-https://golang.org/pkg/math/big 7 | - `unicode`标准库的官方文档-https://golang.org/pkg/unicode 8 | - 开始阅读官方的Go语言规范吧-https://golang.org/ref/spec 9 | 10 | -------------------------------------------------------------------------------- /eBook/chapter5/05.0.md: -------------------------------------------------------------------------------- 1 | ### 数据结构 2 | 3 | 在上一章中,我们讨论了可以通过`struct`关键字定义的组合类型,正则表达式,模式匹配,元组,`runes`,字符串,`unicode`和`strings`包,之后我们开发了一个简单的`key-value`存储。但是有时候编程语言提供的这些结构不适合一些特定的问题。有些时候我们需要自己创建的数据结构,以便以准确,专业的方式去存储,搜索,接收数据。因此,本章将介绍在Go中开发和使用众所周知的数据结构,包括二叉树,链表,散列表,堆栈和队列以及了解它们的优点。由于没有比图像更好地描述数据结构,因此本章将会看到许多图解!本章最后一部分将讨论随机数的生成,它将会帮你生成难以猜测的密码!下面是本章的内容概览: 4 | 5 | - 图和节点 6 | - 分析算法复杂度 7 | - Go的二叉树 8 | - Go的哈希表 9 | - Go的链表 10 | - Go的双端链表 11 | - Go的队列 12 | - Go的栈 13 | - Go标准库`container`包提供的数据结构 14 | - Go生成随机数 15 | - 构建随机字符串用作难以破解的密码 16 | 17 | -------------------------------------------------------------------------------- /eBook/chapter5/05.1.md: -------------------------------------------------------------------------------- 1 | ### 图和节点 2 | 3 | 图G(V,E)是由一组有限的,非空的顶点集V(或者节点)以及一组边E组成。有两种主要的类型:有环图和无环图。有环图是指其全部或者部分顶点集存在闭环。在无环中,没有闭环。有向图是其边有方向性,有向无环图是没有闭环的有向图。 4 | 5 | 通常一个节点(node)包含很多信息,所以node一般使用Go的数据结构来实现 -------------------------------------------------------------------------------- /eBook/chapter5/05.11.md: -------------------------------------------------------------------------------- 1 | ### 延展阅读 2 | 3 | 下面这些资源很有用: 4 | 5 | * 仔细查看 **Graphviz** 程序的网页。你可以使用这个程序提供的语言画图:http://graphviz.org。 6 | * 查看 https://golang.org/pkg/container 并阅读 Go 标准库 `container` 中子包的文档页面。 7 | * 如果你想进一步了解数据结构的话可以阅读 *Alfred V.Aho*、*John E.Hopcroft* 和 *Jeffrey D.Ullman* 写的 *The Design and Analysis of Computer Algorithms (Addison-Wesley, 1974)*,这本书非常棒! 8 | * 还有基本关于算法和数据结构的书也很有趣,分别是 *Programming Pearls (Addison-Wesley Professional, 1999)* 和 *More Programming Pearls: Confessions of a Coder (Addison-Wesley Professional, 1988)*,这两本书都是 *John Bentley* 写的。好好读这两本书可以让你成为一个更优秀的程序员! -------------------------------------------------------------------------------- /eBook/chapter5/05.12.md: -------------------------------------------------------------------------------- 1 | ### 练习 2 | 3 | * 尝试修改将 `generatePassword.go` 背后的逻辑,新的程序将使用当前系统时间或日期生成一个 Go 切片,然后使用这个切片生成一个密码列表,再从中挑选一个密码。 4 | * 修改 `queue.go` 的代码使其能够存储浮点数而不是整数。 5 | * 修改 `stack.go` 的代码,使其节点拥有 `Value`、`Number` 和 `Seed` 三个整型的数据字段。除了明显要对 `Nodestruct` 的定义进行修改,你还需要对剩下的程序做出什么改动? 6 | * 你能试试修改 `linkedList.go` 的代码,使其能够保持链表中的节点有序吗? 7 | * 类似的,你能修改 `doublyLList.go` 中代码使其能保持节点有序吗?你能开发一个删除已存在节点的函数吗? 8 | * 修改 `hashTableLookup.go` 的代码使得哈希表中没有重复的元素。你可以使用 `lookup()` 函数! 9 | * 你能修改 `generatePassword.go` 中的代码使生成的密码只包含大写字母吗? 10 | * 试试修改 `conHeap.go` 使其除了能支持 `float32` 元素外还能支持自定义的、更复杂的结构。 11 | * 实现 `linkedList.go` 中缺失的删除节点的功能。 12 | * 你觉得如果使用双向链表的话是否能改善 `queue.go` 程序中的代码呢?试着用双向链表代替单向链表实现一个队列。 -------------------------------------------------------------------------------- /eBook/chapter5/05.13.md: -------------------------------------------------------------------------------- 1 | ### 本章小结 2 | 3 | 在这一章中我们讨论了很多 Go 语言数据结构相关的有趣又实用的话题,包括链表、双向链表、哈希表、队列和栈的实现,还有 Go 语言标准库 `container` 的用法以及如何使用 Go 生成随机数和难以猜测的密码。通过学习这一章你应该记住,每种数据结构的基础都是其中节点的定义和实现。 4 | 5 | 我确信你会觉得下一章是本书中最有趣并且最有价值的一章。下一章的主题是 Go 语言的包。下一章还介绍了如何在你的程序中定义并使用各种类型的 Go 函数。所以别耽误时间了,继续往后看吧! -------------------------------------------------------------------------------- /eBook/chapter5/05.2.md: -------------------------------------------------------------------------------- 1 | ### 算法复杂度 2 | 3 | 算法的效率是由计算的复杂度来判定的,这主要是和算法完成工作需要访问其输入数据的次数有关。 4 | 5 | 在计算机科学中通常用大`O`表示法来描述算法的复杂度。因此,只需要访问线性次输入数据的O(n)算法要更优于O(n2)的算法以及O(n3)的算法等等。然而最坏的算法就是O(n!),想输入超过300个元素是不可能的。 6 | 7 | 最后,Go大多数内置数据类型的查找操作,例如map中通过key查找value或者访问数组元素都是常量时间内完成即O(1)。这就意味着内置数据类型通常比自定义类型更快,所以你应该优先使用它们,除非你想完全控制幕后发生的事情。此外并非所有的数据结构都相同,通常来讲数组操作数据比map要快,这也是你必须为map的多功能性付出的代价。 8 | 9 | 尽管每种算法都有他的缺点,但是如果你的数据量不是很大的时候,只要算法能够准确的执行所需的工作,那么这些就不是很重要了。 -------------------------------------------------------------------------------- /eBook/chapter5/05.3.2.md: -------------------------------------------------------------------------------- 1 | ### 二叉树的优点 2 | 3 | 当你要描述多层次数据的时候,树是最好的选择。因此,树被广泛应用于编程语言的编译器解析计算机程序的过程。 4 | 5 | 此外,树本身就具有**有序性**,所以你不必另外对其进行排序。只要插入到了正确的位置,那么树就能保持有序。然而,由于树的构造方式,删除元素的操作有时至关重要。 6 | 7 | 如果一个二叉树是平衡的,它的查找、插入、删除操作需要 *log(n)* 步,这里的 n 是树上元素的总数量。此外,平衡二叉树的高度约为 *log2(n)*,这意味着一个拥有 10,000 个元素的平衡树的高度大约是 14。类似的,拥有 100,000 个元素的平衡树的高度大约是 17,拥有 1,000,000 个元素的平衡树的高度大约是 20。也就是说,向一个平衡二叉树中插入大量的元素后,对树进行操作的速度并不会大幅变化。换个说法,你只需要不到 20 步就能到达一个拥有 1,000,000 个节点的树上的任意一个节点! 8 | 9 | 二叉树最大的一个缺点是树的形状很依赖元素插入的顺序。如果树上元素的键又长又复杂,那么插入和查找元素的过程需要进行大量的匹配,从而变得很慢。最后,如果一个树不是平衡的,那么就很难对其性能进行预测。 10 | 11 | 尽管你能更快地创建链表或数组,但是二叉树在查找操作中的灵活性值得付出额外的开销并进行维护。在二叉树上查找一个元素时,你会比较要搜索的元素则值与当前节点值的大小,然后决定在哪个子树上继续搜索,这样做可以节约大量的时间。 12 | -------------------------------------------------------------------------------- /eBook/chapter5/05.3.md: -------------------------------------------------------------------------------- 1 | ### Go 语言中的二叉树 2 | 3 | **二叉树**是每个节点最多有两个分支的数据结构。“最多”表示一个节点可以连接一至两个子节点,或者不连接其他子节点。**树的根节点**是树结构中的第一个节点。**树的深度**,又称为树的高度,是从树的根节点到所有节点的路径中最长的一个。而节点的深度是该节点到树的根所经过的路径中边的数量。**叶节点**是没有子节点的节点。 4 | 5 | 若一个树的根节点到任意两个叶节点的距离之差不大于 1,则认为这个树是**平衡的**。顾名思义,非平衡树不是平衡的。树的平衡操作困难又缓慢,所以最好从一开始就让你的树保持平衡,而不是在建好树之后再去调整,尤其是这个树有很多节点的时候。 6 | 7 | 下图是一个非平衡二叉树。它的节根点是 J,叶节点包括 A、G、W 和 D。 8 | 9 | ![](../../images/chapter5/05.3-1.jpg) 10 | -------------------------------------------------------------------------------- /eBook/chapter5/05.4.2.md: -------------------------------------------------------------------------------- 1 | ### 实现查找功能 2 | 3 | 在这一节中,你将会实现一个 `lookup()` 函数,使用这个函数可以检查哈希表中是否已经存在某个给定的元素。`lookup()` 函数基于 `traverse()` 函数实现,如下所示: 4 | 5 | ```go 6 | func lookup(hash *HashTable, value int) bool { 7 | index := hashFunction(value, hash.Size) 8 | if hash.Table[index] != nil { 9 | t := hash.Table[index] 10 | for t != nil { 11 | if t.Value == value { 12 | return true 13 | } 14 | t = t.Next 15 | } 16 | } 17 | return false 18 | } 19 | ``` 20 | 21 | 你可以在 `hashTableLookup.go` 源文件中找到上面的代码。执行 `hashTableLookup.go` 将得到下面的输出: 22 | 23 | ```go 24 | $ go run hashTableLookup.go 25 | 120 is not in the hash table! 26 | 121 is not in the hash table! 27 | 122 is not in the hash table! 28 | 123 is not in the hash table! 29 | 124 is not in the hash table! 30 | ``` 31 | 32 | 以上的输出表示 `lookup()` 函数效果很棒! 33 | -------------------------------------------------------------------------------- /eBook/chapter5/05.4.3.md: -------------------------------------------------------------------------------- 1 | ### 哈希表的优点 2 | 3 | 如果你认为哈希表不实用、不方便或者不巧妙,请考虑如下情形:当一个哈希表有 n 个键和 k 个桶时,查找 n 个键的时间复杂度将从使用线性查找的 *O(n)* 下降至 *O(n/k)*!尽管这点改进看起来不起眼,你也必须意识到对于一个有 20 个槽的哈希数组,查找的次数将会下降为原来的 1/20!这让哈希表非常适合用于搭建词典或者其他这类需要大量数据查找的应用。 -------------------------------------------------------------------------------- /eBook/chapter5/05.4.md: -------------------------------------------------------------------------------- 1 | ### Go 语言中的哈希表 2 | 3 | 严格来讲,**哈希表**这种数据结构会存储一至多个键值对,并使用一个哈希函数计算出存放正确值的桶或槽的索引。理想情况下,**哈希函数**应该将每个键分配到唯一的桶中,但通常你事先得有足够数量的桶。 4 | 5 | 一个好的哈希函数一定要能够输出均匀分布的哈希值,如果有多余的桶或者桶之间的基数差值较大,操作的效率就会变低。此外,这个哈希函数应该具有一致性,对于同一个键始终输出相同的哈希值,否则就不能准确定位需要的数据。 6 | 7 | 下图展示了一个拥有 10 个桶的哈希表。 8 | 9 | ![](../../images/chapter5/05.4-1.jpg) -------------------------------------------------------------------------------- /eBook/chapter5/05.5.2.md: -------------------------------------------------------------------------------- 1 | ### 链表的优点 2 | 3 | 链表最大的优点就是容易理解和实现。链表的通用性使得它们可以用于很多不同的情形。这意味着可以用链表对各种不同类型的数据建模。此外,在链表中使用指针进行顺序检索的速度非常快。 4 | 5 | 链表不仅可以对数据排序,还可以在插入和删除元素之后保持数据的有序性。从有序链表中删除一个节点的操作与无序链表中相同,而向有序链表中插入新的节点则与无序链表中不同,为了保持链表的有序性,必须将新节点放到正确的位置。实际上,这意味着如果你有大量数据并且会频繁删除数据,那么相对于哈希表和二叉树,使用链表是一个更好的选择。 6 | 7 | 最后,有很多技术可以优化**有序链表**中搜索和查找节点的过程。其中最常用的一种就是保存一个指向有序链表中间节点的指针,之后每次都从这个节点开始查找。这个简单的优化方法可以将查找操作的时间减少一半! -------------------------------------------------------------------------------- /eBook/chapter5/05.5.md: -------------------------------------------------------------------------------- 1 | ### Go 语言中的链表 2 | 3 | **链表**是一种包含有限个元素的数据结构,其中每个元素至少占用两个存储单元,一个用于存储真正的数据,另一个用于存储链接当前元素和下一个元素的指针,从而建立了一个元素序列构成的链表。 4 | 5 | 链表中的第一个元素称为头,最后一个元素称为尾。在定义链表的过程中,你需要做的第一件事就是将链表头用单独的变量存储,因为链表头是你访问整个链表的唯一媒介。注意,如果弄丢了指向单向链表第一个节点的指针,你就没法再找到它了。 6 | 7 | 下图展示了一个拥有五个节点的链表: 8 | 9 | ![](../../images/chapter5/05.5-1.jpg) 10 | 11 | 下图描述了如何从链表中移除一个节点,它将帮助你更好地理解这个过程所涉及的步骤。你要做的主要是修改被删除节点左侧的那个节点,将它指向下一个元素的指针指向被删除节点右侧的那个节点。 12 | 13 | ![](../../images/chapter5/05.5-2.jpg) 14 | 15 | 下面的链表实现已经相对简化了,并且不含删除节点的功能,这个功能的实现将留给读者作为练习题。 -------------------------------------------------------------------------------- /eBook/chapter5/05.6.2.md: -------------------------------------------------------------------------------- 1 | ### 双向链表的优点 2 | 3 | 双向链表的功能比单向链表更加丰富,你可以从任意方向遍历双向链表,也可更容易地在双向链表中增删元素。此外,即使弄丢了指向双向链表头节点的指针,你也可以重新找回它。然而,这种多功能性的代价就是每个节点需要维护两个指针。开发者需要考虑这种额外的复杂性是否值得。 4 | 5 | 总之,你的音乐播放器中的歌单用的可能就是双向链表,所以你才能切换到上一首歌和下一首歌! -------------------------------------------------------------------------------- /eBook/chapter5/05.6.md: -------------------------------------------------------------------------------- 1 | ### Go 语言中的双向链表 2 | 3 | **双向链表**中的每个节点都既有指向前一个元素的指针,又有指向下一个元素的指针。 4 | 5 | 双向链表形如下图: 6 | 7 | ![](../../images/chapter5/05.6-1.jpg) 8 | 9 | 因此,在一个双向链表中,第一个节点的后链接指向第二个节点,而它的前链接指向 `nil`(也称为 **NULL**)。类似的,最后一个节点的后链接指向 `nil`,而它的前链接指向双向链表中的倒数第二个节点。 10 | 11 | 本章的最后一个插图阐明了双向链表中增加节点的操作。可想而知,这个过程中的主要任务是处理新节点、新节点左侧节点、新节点右侧节点这三个节点的指针。 12 | 13 | ![](../../images/chapter5/05.6-2.jpg) 14 | 15 | 所以,单向链表和双向链表的主要区别实际上只是双向链表的操作更冗杂。这是你为了能够从两个方向都能访问双向链表所必须付出的代价。 -------------------------------------------------------------------------------- /eBook/chapter5/05.7.md: -------------------------------------------------------------------------------- 1 | ### Go 语言中的队列 2 | 3 | **队列**是一种特殊的链表,它总是在链表头添加新的元素,在链表尾删除元素。我们不必用插图来描述队列。想象一下银行中的情形,你必须等到比你先来的人完成交易之后才能和出纳员交谈。这就是个队列! 4 | 5 | 队列最大的优点就是简单!你只需要两个函数就能访问一个队列,这意味着你需要担心的事情更少,并且你只用完成这两个函数就能实现一个队列! -------------------------------------------------------------------------------- /eBook/chapter5/05.8.md: -------------------------------------------------------------------------------- 1 | ### Go 语言中的栈 2 | 3 | **栈**是一种看起来像一堆盘子的数据结构。你在需要一个新盘子时会先使用最后一个被放在这堆盘子顶端的那个盘子。 4 | 5 | 栈最大的优点就是简单,因为你只需要实现两个函数就能使用栈,之后你可以向栈中添加新节点或者删除栈中的节点。 6 | -------------------------------------------------------------------------------- /eBook/chapter5/05.9.md: -------------------------------------------------------------------------------- 1 | ### container 包 2 | 3 | 在这一节中,我会介绍 Go 语言标准库 `container` 的用法。`container` 包支持三种数据结构:`heap`、`list` 和 `ring`。`container/heap`、`container/list` 和 `container/ring` 分别实现了这些数据结构。 4 | 5 | 有的人可能对环不太熟悉,环就是一个**循环链表**,也就是说环上的最后一个元素中的指针指向环上的第一个元素。从根本上来说,这意味着环上的每个节点都是平等的,并且没有开头和结尾。因此,从环上任一元素开始都能遍历整个环。 6 | 7 | 后面的三个小节将分别详细介绍 `container` 包中的每一个包。有个合理的建议:你应该先判断 Go 语言标准库 `container` 的功能是否满足你的需求,如果满足再加以使用,否则你应该使用自己实现的数据结构。 -------------------------------------------------------------------------------- /eBook/chapter6/06.0.md: -------------------------------------------------------------------------------- 1 | # Go package中不为人知的知识 2 | 3 | 上章,我们讨论了开发和使用自定义数据结构,如链表,字节树,哈希表,还有生产随机数和用 Go 猜测密码。 4 | 5 | 这章主要讲 Go package,它是 Go 组织,交付,使用代码的方式。Go package 非常通用的组成部分是 **函数**,它相当的灵活。这章的最后部分您将看到一些高级的 Go 标准库 package,会更好地理解创建 Go package 的不同方式。 6 | 7 | 这章,您将了解到如下主题: 8 | 9 | + 用 Go 编写函数 10 | + 匿名函数 11 | + 返回多值函数 12 | + 命名函数的返回值 13 | + 返回其他函数的函数 14 | + 函数作为参数的函数 15 | + 编写 Go package 16 | + 私有和公有 package 对象 17 | + 在包中使用 `init()` 函数 18 | + 复杂的 `html/templates` 标准 package 19 | + `text/template` 标准 package,和另一个真正复杂的有自己语言的 Go package 20 | + `syscall` 标准包,它是一个底层的包,尽管您可能很少有机会使用它,但它被其他包广泛使用。 -------------------------------------------------------------------------------- /eBook/chapter6/06.1.md: -------------------------------------------------------------------------------- 1 | # 关于Go packages 2 | 3 | 在 Go 中所有东西都以 packages 形式传递。Go **package** 是 Go 源文件,它以 `package` 关键字开头后面跟着这个 package 的名字。一些 packages 有结构。例如,`net` package 有几个子目录,分别是 `http, mail, rpc, smtp, textproto` 和 `url`,它们应该分别依 `net/http, net/mail, net/rpc, net/smtp, net/textproto` 和 `net/url` 引入。 4 | 5 | packages 主要用于组合相关函数,变量和常量,以便您可以在自己的程序中简单地传递和使用它们。注意 `main` package 里的内容,Go packages 不是自控制程序并且不能被编译为可执行文件。这意味着他们需要直接或间接的在 `main` package 里调用才能使用。因此,如果您把它当成自控制程序来执行,您会失望的: 6 | 7 | ```shell 8 | $go run aPakcage.go 9 | go run: cannot run non-main package 10 | ``` -------------------------------------------------------------------------------- /eBook/chapter6/06.2.1.md: -------------------------------------------------------------------------------- 1 | # 匿名函数 2 | 3 | **匿名函数** 可以在不需要名称的情况下直接定义,它们通常用于实现只需很少代码量的功能。Go 中,函数可以返回一个匿名函数或把匿名函数作为它的参数。另外,匿名函数可以分配给变量。 4 | 5 | 注意匿名函数也叫**闭包**,特别是在函数式编程术语中。 6 | 7 | > *匿名函数好的表现是实现内容小并聚焦局部。如果一个匿名函数没有聚焦局部,那么您可能需要把它改为正常函数* 8 | 9 | 当匿名函数适合一个功能时,它极其方便和容易;只是在没有好的原因时不要使用太多匿名函数。您稍后会看到匿名函数是如何工作的。 -------------------------------------------------------------------------------- /eBook/chapter6/06.2.4.md: -------------------------------------------------------------------------------- 1 | # 参数为指针的函数 2 | 3 | 函数可以有指针类型的参数。`ptrFun.go` 的代码将说明指针作为函数参数的使用。 4 | 5 | `ptfFun.go` 的第一部分如下: 6 | 7 | ```go 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | ) 13 | 14 | func getPtr(v *float64) float64 { 15 | return *v * *v 16 | } 17 | ``` 18 | 19 | `getPrt()` 函数接收一个指向 `float64` 值的指针。 20 | 21 | 第二段代码如下: 22 | 23 | ```go 24 | func main() { 25 | x := 12.2 26 | fmt.Println(getPrt(&x)) 27 | x = 12 28 | fmt.Println(getPtr(&x)) 29 | } 30 | ``` 31 | 32 | 这里您需要传递变量的地址给 `getPtr()` 函数,因为它需要一个指针参数,传地址需要在变量前放一个 & 符号(&x)。 33 | 34 | 执行 `ptrFun.go` 产生如下输出: 35 | 36 | ```shell 37 | $go run ptrFun.go 38 | 148.83999999999997 39 | 144 40 | ``` 41 | 42 | 如果您直接传值如:`12.2` 给 `getPtr()`,并调用它如:`getPtr(12.12)`,那么程序编译失败,显示下面的错误信息: 43 | 44 | ```shell 45 | $go run ptrFun.go 46 | # command-line-arguments 47 | ./ptrFun.go:15:21: cannot use 12.12 (type float64) as type *float64 in argument to getPtr 48 | ``` -------------------------------------------------------------------------------- /eBook/chapter6/06.2.5.md: -------------------------------------------------------------------------------- 1 | # 返回值为指针的函数 2 | 3 | 如您在[第四章](https://github.com/hantmac/Mastering_Go_ZH_CN/blob/master/eBook/chapter4/04.0.md)了解到的,在 `pointerStruct.go` 程序中介绍的*复合类型的使用*,它是一个非常好的练习,使用一个独立的函数来创建一个新的结构变量并返回指向它的指针。因此,函数返回指针是非常常见的。通常讲,函数简化程序结构并让开发者把较重要的处理逻辑集中起来,而不是总是复制相同的代码。这节将使用一个非常简单的例子,`returnPtr.go`。 4 | 5 | `returnPtr.go` 的第一部分代码如下: 6 | 7 | ```go 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | ) 13 | 14 | func returnPtr(x int) *int { 15 | y := x * x 16 | return &y 17 | } 18 | ``` 19 | 20 | 除了必须的引入部分,这段代码定义了一个返回 `int` 变量指针的新函数。唯一要记住的是使用 `&y` 在 `return` 表达式来返回 `y` 变量的内存地址。 21 | 22 | `returnPtr.go` 的第二部分如下: 23 | 24 | ```go 25 | func main() { 26 | sq := returnPtr(10) 27 | fmt.Println("sq:", *sq) 28 | ``` 29 | 30 | 如您所知,`*` 符号**解引用一个指针变量**,就是它返回存储在内存地址里的实际值而不是内存地址本身。 31 | 32 | `returnPtr.go` 的最后一段代码如下: 33 | 34 | ```go 35 | fmt.Println("sq:", sq) 36 | } 37 | ``` 38 | 39 | 这段代码返回 `sq` 变量的内存地址,而不是存储在它里面的 `int` 值。 40 | 41 | 执行 `returnPtr.go` 将看到如下输出(内存地址可能会不同): 42 | 43 | ```shell 44 | $go run returnPtr.go 45 | sq: 100 46 | sq: 0xc420014088 47 | ``` 48 | -------------------------------------------------------------------------------- /eBook/chapter6/06.2.6.md: -------------------------------------------------------------------------------- 1 | # 闭包 2 | 3 | 这节,您将了解到使用 `returnFunction.go` 的代码怎样实现闭包,分为三部分来介绍。 4 | 5 | `returnFunction.go` 的第一部分如下: 6 | 7 | ```go 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | ) 13 | 14 | func funReturnFun() func() int { 15 | i := 0 16 | return func() int { 17 | i++ 18 | return i * i 19 | } 20 | } 21 | ``` 22 | 23 | 如您所见,`funReturnFun()` 函数返回一个匿名函数! 24 | 25 | `returnFunction.go` 的第二段代码如下: 26 | 27 | ```go 28 | func main(){ 29 | i := funReturnFun() 30 | j := funReturnFun() 31 | ``` 32 | 33 | 这段代码,调用 `funReturnFun()` 俩次并分配函数类型的返回值给名为 `i` 和 `j` 的两个特定变量。从程序的输出可以看出,这两个变量是完全无关的。 34 | 35 | `returnFunction.go` 的最后一段代码如下: 36 | 37 | ```go 38 | fmt.Println("1:", i()) 39 | fmt.Println("2:", i()) 40 | fmt.Println("j1:", j()) 41 | fmt.Println("j2:", j()) 42 | fmt.Println("3:", i()) 43 | } 44 | ``` 45 | 46 | 这段代码里,以 `i()` 使用 `i` 变量三次,以 `j()` 使用 `j` 变量两次。重要的是尽管 `i` 和 `j` 是由调用 `funReturnFun()` 创建,但它们完全独立,不共享任何内容。所以,尽管它们从同样的序列返回值但它们彼此不干扰。 47 | 48 | 执行 `returnFunction.go` 产生如下输出: 49 | 50 | ```shell 51 | $go run returnFunction.go 52 | 1: 1 53 | 2: 4 54 | j1: 1 55 | j2: 4 56 | 3: 9 57 | ``` 58 | 59 | 从 `returnFunction.go` 的输出可以看到,`funReturnFun()` 函数里的 `i` 值保持增加并不会在每次调用 `i()` 或 `j()` 后变为 `0`。 -------------------------------------------------------------------------------- /eBook/chapter6/06.2.7.md: -------------------------------------------------------------------------------- 1 | # 函数作为参数 2 | 3 | Go 函数可以接收另一个 Go 函数作为参数,这个功能为您用 Go 函数增加了非常广泛的用途。这个功能最为常用的用途就是闭包。这里介绍的 `funFun.go`,是一个非常简单的处理整数值的例子。相关代码分为三部分介绍。 4 | 5 | `funFun.go` 的第一部分代码如下: 6 | 7 | ```go 8 | package main 9 | 10 | import "fmt" 11 | 12 | func function1(i int) int { 13 | return i + i 14 | } 15 | 16 | func function2(i int) int { 17 | return i * i 18 | } 19 | ``` 20 | 21 | 这里是两个接收 `int` 并返回 `int` 的函数。它们一会用于作为另个函数的参数。 22 | 23 | `funFun.go` 的第二段函数包含如下代码: 24 | 25 | ```go 26 | func funFun(f func(int) int, v int) int { 27 | return f(v) 28 | } 29 | ``` 30 | 31 | `funFun()` 函数接收两个参数,一个名为 `f` 的函数和一个 `int` 值。`f` 参数是一个接收 `int` 参数并返回 `int` 值的函数。 32 | 33 | `funFun.go` 的最后一段如下: 34 | 35 | ```go 36 | func main() { 37 | fmt.Println("function1:", funFun(function1, 123)) 38 | fmt.Println("function2:", funFun(function2, 123)) 39 | fmt.Println("Inline:", funFun(func(i int) int {return i * i * i}, 123)) 40 | } 41 | ``` 42 | 43 | 第一个 `fmt.Println()` 调用使用 `function1` 作为第一个参数的 `funFun()`,第二个 `fmt.Println()` 调用使用 `function2` 作为第一个参数的 `funFun()`。 44 | 45 | 最后一个 `fmt.Println()` 表达式,奇妙的是:这个函数参数的实现定义在 `funFun()` 调用里! 46 | 47 | 尽管这个方法可以运行简单的,小巧的函数参数,对于多行代码的函数还是尽量不要这样使用。 48 | 49 | 执行 `funFun.go` 将产生如下输出: 50 | 51 | ```shell 52 | $go run funFun.go 53 | function1: 246 54 | function2: 15129 55 | Inline: 1860867 56 | ``` 57 | -------------------------------------------------------------------------------- /eBook/chapter6/06.2.md: -------------------------------------------------------------------------------- 1 | # Go函数 2 | 3 | **函数** 在任何编程语言中都是重要的元素,因为它可以让您把大块的程序分成比较小而且好管理的小块。函数必须尽可能的彼此独立,而且必须完成单一功能,最好只做一个功能。因此,如果您发现您写的函数做了多个功能,那么您需要考虑用多个函数来取代它!Go 中唯一最常用的函数是 `main()`,它被用在每个独立的 Go 程序中。您应该已经知道了函数的定义用 `func` 关键字开始。 -------------------------------------------------------------------------------- /eBook/chapter7/07.0.md: -------------------------------------------------------------------------------- 1 | # **反射和接口** 2 | 3 | 在前一章中,我们讨论了如何在Go中编写包和函数。我们还讨论了如何使用```text/template```和```html/template```包进行文本和HTML模版的开发。最后,我们解释了```syscall```包的使用方法。 4 | 5 | 在这一章中,您将学习三个非常有趣、方便和有点高级Go概念:反射、接口和类型方法。Go接口经常被使用,反射在程序中使用频率较低,而类型方法则是包含Go语言中类型断言和面向对象编程(OOP)的知识。 6 | 7 | 在本章中,您将学习以下主题: 8 | - 类型方法 9 | - Go接口 10 | - 类型断言 11 | - 设计接口 12 | - Go的OOP思想 13 | - 反射和标准Go包```reflect``` -------------------------------------------------------------------------------- /eBook/chapter7/07.2.md: -------------------------------------------------------------------------------- 1 | # **Go的接口** 2 | 3 | 严格来说,Go的```interface```类型是一组需要被其他数据类型实现的函数方法的集合。对于需要满足接口的数据类型,它需要实现接口所需的所有方法。简单地说,接口是定义了一组需要被实现的函数方法的**抽象类型**,实现接口的数据类型可以视为接口的实例。如果满足以上情况,我们说数据类型实现了这个接口。因此,一个接口包含两部分:一组接口方法和一个接口类型,这样就可以定义其它数据类型的行为。 4 | 5 | 使用接口的最大优势,就是在定义函数时使用接口作为参数,那么在调用函数时,任何实现该接口类型的变量都可以作为函数的参数被传递。接口可以作为抽象类型的能力,是其最实际的价值。 6 | 7 | > 如果发现在同一个Go包中定义了一个接口及其实现,那么可能使用了错误的接口实现方式! 8 | 9 | 两个非常常见的Go接口是```io.Reader```和```io.Writer```,用于文件输入和输出操作。具体来说,```io.Reader```用于读取文件,而```io.Writer```用于写入文件。 10 | 11 | 在代码[https://golang.org/src/io/io.go](https://golang.org/src/io/io.go)中,```io.Reader```的定义如下: 12 | 13 | >```go 14 | > type Reader interface { 15 | > Read(p []byte) (n int, err error) 16 | > } 17 | >``` 18 | 19 | 为了使类型满足```io.Reader```接口,需要实现接口中描述的```Read()```方法。 20 | 21 | 同样,在代码[https://golang.org/src/io/io.go](https://golang.org/src/io/io.go)中的```io.Writer```的定义如下: 22 | 23 | >```go 24 | > type Writer interface { 25 | > Write(p []byte) (n int, err error) 26 | > } 27 | >``` 28 | 29 | 为满足```io.Writer```接口,只需要实现一个名为```Write()```的方法。 30 | 31 | 尽管每个```io.Reader```和```io.Writer```接口都只需要实现一个方法,但是这两个接口功能都非常强大。他们功能的强大都源于他们的简单!一般来说,接口应该尽可能简单。 32 | 33 | 在下一章节中,将讲解如何定义一个接口,以及如何在其他Go包中使用。需要注意的是一个接口只要做想要实现的事情,不需要过于花哨或令人印象深刻。 34 | 35 | > 简单地说,当需要一个Go元素确保满足某些条件或者达到某些预期行为时,应该使用接口。 -------------------------------------------------------------------------------- /eBook/chapter7/07.4.md: -------------------------------------------------------------------------------- 1 | # **设计接口** 2 | 3 | 在本节中,您将学习如何设计接口。只要您知道要设计的接口行为,这个过程是相对简单的。 4 | 5 | 该章节将使用Go代码```myInterface.go```进行说明,这个代码将创建一个接口来辅助平面的几何图形的相关运算。 6 | 7 | ```myInterface.go```的Go代码如下: 8 | 9 | >```go 10 | > package myInterface 11 | > 12 | > type Shape interface { 13 | > Area() float64 14 | > Perimeter() float64 15 | > } 16 | >``` 17 | 18 | 接口```shape```的定义是非常简单直接的,它只需要实现两个名为```Area()```和```Perimeter()```的函数,两个函数都返回```float64```值。第一个函数将用于计算平面形状的面积,第二个函数用于计算平面形状的周长。之后,您需要安装```myInterface.go```包,并使其对当前用户可用。正如你已经知道的,安装过程涉及以下Unix命令的执行: 19 | 20 | >```shell 21 | > $ mkdir ~/go/src/myInterface 22 | > $ cp myInterface.go ~/go/src/myInterface 23 | > $ go install myInterface 24 | >``` -------------------------------------------------------------------------------- /eBook/chapter7/07.5.3.md: -------------------------------------------------------------------------------- 1 | # **反射的三个缺点** 2 | 3 | 毫无疑问,反射是Go语言一个强大的功能。然而,由于所有工具都使用反射,因此应谨慎使用,主要有三个原因。 4 | 5 | 第一个原因是反射的广泛使用会使程序难以阅读和维护。这个问题的一个潜在解决方案是编写好的文档;但众所周知的是开发人员并不愿意花时间来编写维护文档。 6 | 7 | 第二个原因是使用反射的Go代码会使程序运行变慢。一般来说,用于特定数据类型的Go代码总是比使用反射动态处理Go数据类型的代码运行速度快。此外,这样的动态代码将使工具很难重构或分析代码。 8 | 9 | 最后一个原因是反射错误在编译时无法捕获,并且运行时会造成```panic```异常。这意味着反射的错误可能会使程序崩溃!这可能发生在Go程序开发完成后的数月甚至数年后!这个问题的一个解决办法是在危险函数调用之前进行全面的测试。然而,这将为Go程序增加更多的代码,使程序运行的更慢。 -------------------------------------------------------------------------------- /eBook/chapter7/07.5.md: -------------------------------------------------------------------------------- 1 | # **反射** 2 | 3 | **反射**是一种高级的Go语言特性,它允许动态地获取任意对象的类型及其结构信息。Go语言通过```reflect```包提供用于处理反射的能力。不过应该记住的是,您很可能不需要在每个Go程序中使用反射。 4 | 5 | 可能会出现的前两个问题是,为什么反射是必要的,什么时候应该使用它? 6 | 7 | 对于诸如```fmt```、```text/template```和```html/template```等包的实现,反射是必需的。在```fmt```包中,反射可以避免必须显式地处理现有的每种数据类型。即使您有耐心编写代码来处理您知道的每种数据类型,您仍然无法处理所有可能的类型!所以在这种情况下,反射使```fmt```包的方法能够同新类型协同工作! 8 | 9 | 因此,当想编写尽可能通用的代码时,或当希望确保能够处理编写时不存在的数据类型代码,都可以使用反射。此外,反射在处理不需要实现公共接口的类型变量的值时,也非常方便。 10 | 11 | > 反射帮助您处理未知类型和未知类型值。 12 | 13 | ```reflect```包的核心有两种类型,分别为```reflect.Value```和```reflect.Type```。前一种类型用于存储任何类型的值,而后一种类型用于表示任意Go类型。 -------------------------------------------------------------------------------- /eBook/chapter7/07.7.md: -------------------------------------------------------------------------------- 1 | # **延展阅读** 2 | 3 | 您会发现以下两项资源非常方便: 4 | 5 | - 访问Go标准包文档中```reflect```包的页面,可在[https://golang.org/pkg/reflect/](https://golang.org/pkg/reflect/)中找到。```relfect```包有比本章介绍更多的功能。 6 | 7 | - 如果你真的对反射很感兴趣并想了解更多关于反射的知识,你可以参考Mitchell Hashimoto的```reflectwalk```库,网址为[https://github.com/mitchellh/reflectwalk](https://github.com/mitchellh/reflectwalk)。```reflectwalk```库允许您在Go语言中使用反射遍历复杂值。如果有时间,可以研究下这个库的Go代码! 8 | -------------------------------------------------------------------------------- /eBook/chapter7/07.8.md: -------------------------------------------------------------------------------- 1 | # **练习** 2 | 3 | - 编写一个接口,并在另一个Go程序中使用它。然后说明你编写的接口的作用。 4 | - 编写一个接口,计算三维图形的体积,例如立方体和球体。 5 | - 编写一个借口,计算线段长度和平面上两点之间的距离。 6 | - 编写一个使用反射的例子。 7 | - 反射如何在Go映射上工作? 8 | - 如果你擅长数学,试着编写一个接口来实现实数和复数的四个基本数学运算。不要使用```complex64```和```complex128```这些标准Go类型,用来定义支持复数的结构。 -------------------------------------------------------------------------------- /eBook/chapter7/07.9.md: -------------------------------------------------------------------------------- 1 | # **本章小结** 2 | 3 | 在本章中,您学习了类似契约的接口,以及Go中的类型方法、类型断言和反射。您还学习了如何遵循面向对象编程原则编写Go代码。 4 | 5 | 虽然反射是一个非常强大的Go特性,但它可能会减慢Go程序的速度,因为它在运行时增加了一层复杂性。此外,如果使用反射时不够仔细,Go程序可能会崩溃。 6 | 7 | 如果要只记住本章中唯一一件事,那就是Go不是面向对象的编程语言,而是可以模仿面向对象编程语言提供的一些功能,例如Java和C++。这意味着,如果计划使用面向对象的编程范式开发软件,那么最好选择Go以外的面向对象的编程语言。当然,面向对象编程并不是万能的,如果您选择像Go语言这样的编程语言,那么一样会创建一个更好、更干净、更健壮的设计! 8 | 9 | 虽然这一章的理论可能比你预期的要多,但下一章会让你的耐心得到回报,因为它将涉及Go语言中的系统编程,将要讨论文件I/O、Unix系统文件的使用、Unix信号的处理以及Unix管道的支持。另外,下一章将讨论如何使用```flag```包支持命令行工具中的多个命令行参数和选项、遍历目录结构、Unix文件权限以及Go标准库的```syscall```包提供的一些高级用法。 10 | 11 | 如果你真的喜欢用Go进行系统编程,那么阅读我的《Go Systems Programming,Packt Publishing,2017》这本书会是个好主意。 -------------------------------------------------------------------------------- /eBook/chapter8/08.0.md: -------------------------------------------------------------------------------- 1 | # Go UNIX系统编程 2 | 3 | 上一章,我们讨论了两个高级的,但有点偏理论的 Go 主题:接口和反射。这章的代码只是理论性的。 4 | 5 | 因为这章的主题是**系统编程**,毕竟 Go 是一门严格的系统编程语言;它的创造者不满意于他们编写系统软件所选择的语言,所以它们决定创造一门新的编程语言。 6 | 7 | > *如果您真的对用 Go做 **系统编程**感兴趣,那么 2017 出版的《Go 系统编程》绝对可以帮助到您。但是,这章包含到一些有趣并有点高级的主题没有出现在我的《Go 系统编程》这本书中* 8 | 9 | 《玩转 Go》的这章,您会了解到如下主题: 10 | 11 | + Unix 进程 12 | + `flag` 包 13 | + `io.Reader`和`io.Writer` 接口的使用 14 | + 用 Go 的 `os/signal` 包处理 Unix **信号** 15 | + 在您的 Unix 系统工具中支持 Unix **管道** 16 | + 读取文本文件 17 | + 读取 CSV 文件 18 | + 写入文件 19 | + `bytes` 包 20 | + `syscall` 包的进阶使用 21 | + 遍历目录结构 22 | + Unix 文件权限 -------------------------------------------------------------------------------- /eBook/chapter8/08.1.md: -------------------------------------------------------------------------------- 1 | 2 | # 关于UNIX进程 3 | 4 | 严格讲,**进程**是一个执行环境,包含指令,用户数据,系统数据和运行中获取的资源。另外,**程序**是一个二进制文件,包含指令和初始化指令时用到的数据,还有进程的用户数据。每次运行进程都被一个无符号整数唯一标识,它叫做**进程 ID**。 5 | 6 | 进程有三种分类:用户进程,守护进程,内核进程。**用户进程**运行在用户空间并且通常没有特殊访问权限。**内存进程**仅在内存空间执行并且可以完全访问所有内存数据结构。**守护进程**是运行在用户空间的程序并且运行在后台不需要一个终端。 7 | 8 | > *C 调用 `fork()` 创建新进程。 `fork()` 的返回值用于程序员在父进程和子进程之间进行分辨。相反,Go 不支持类似功能而是提供 goroutines* 9 | 10 | -------------------------------------------------------------------------------- /eBook/chapter8/08.13.md: -------------------------------------------------------------------------------- 1 | #**文件权限** 2 | 3 | `Unix`系统编程中的一个热门话题是`Unix`文件权限。在本节中,假设你有足够的`Unix`权限,你将学习如何输出任意文件的权限!程序名为`permission.go`,分为三部分。 4 | 5 | `permission.go`的第一部分代码如下: 6 | 7 | ```go 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | "os" 13 | ) 14 | ``` 15 | 16 | `permission.go`的第二部分代码如下: 17 | 18 | ```go 19 | func main() { 20 | arguments := os.Args 21 | if len(arguments) == 1 { 22 | fmt.Printf("usage:permissions filename\n") 23 | return 24 | } 25 | ``` 26 | 27 | 最后一部分代码如下: 28 | 29 | ```go 30 | filename := arguments[1] 31 | info, _ := os.Stat(filename) 32 | mode := info.Mode() 33 | fmt.Println(filename, "mode is", mode.String()[1:10]) 34 | } 35 | ``` 36 | 37 | `os.Stat(filename)`调用返回一个大结构体,其中包含了许多数据。因为我们只对文件的权限感兴趣,我们调用`Mode()`方式并打印输出。实际上,我们通过`mode.String()[1:10]`打印了输出的一部分,因为它即是我们感兴趣的那部分。 38 | 39 | 执行`permission.go`将产生如下输出: 40 | 41 | ```shell 42 | $ go run permission.go /tmp/adobegc.log 43 | /tmp/adobegc.log mode is rw-rw-rw- 44 | $ go run permissions.go /dev/random 45 | /dev/random mode is crw-rw-rw 46 | ``` 47 | 48 | `ls(1)`输出可以验证`permission.go`的正确性: 49 | 50 | ```shel 51 | $ ls -l /dev/random /tmp/adobegc.log 52 | crw-rw-rw- 1 root wheel 14, 0 Jan 8 20:24 /dev/random 53 | -rw-rw-rw- 1 root wheel 583454 Jan 16 19:12 /tmp/adobegc.log 54 | ``` 55 | 56 | -------------------------------------------------------------------------------- /eBook/chapter8/08.14.md: -------------------------------------------------------------------------------- 1 | #**处理`Unix`信号** 2 | 3 | `Go`为程序员提供了`os/signal`包来处理信号。本节将向你显示如何处理`Unix`信号。 4 | 5 | 首先,让我们介绍`Unix`信号的一些有用信息。你是否使用`Ctrl+C`停止正在运行的程序?如果是,则它们已经比较相似,因为`Ctrl+C`向程序发送`SIGINT signal`。严格来讲,`Unix`信号是可以通过名称或数字访问的软件中断,它们提供了在`Unix`系统上处理异步事件的方法。有两种方式发送信号:通过名字或者通过数字。通常来说,通过名字发送信号比较安全,因为你不太可能不小心发出错误的信号。 6 | 7 | 一个程序是不可能处理所有的信号的:一些信号既不能被捕获,也不能被忽略。`SIGKILL`和`SIGSTOP`信号不能被捕获、阻塞或忽略。这样做的原因是,它们为内核和根用户提供了一种停止任何进程的方法。`SIGKILL`信号,即数字`9`,通常在需要响应迅速的极端条件下调用。因此,它是唯一一个通常由数字调用的信号,这仅仅是因为这样做更快。 8 | 9 | > *`signal.SIGINFO`在`Linux`机器上不可用。这意味着,如果你要在一个`Linux`机器上运行包含它的`Go`程序,则需要用另一个信号替换它,否则`Go`程序将无法编译和执行。* 10 | 11 | 给进程发送信号的最常用方式是通过`kill(1)`方法。默认情况下,`kill(1)`发送`SIGTERM`信号。如果你想查看`Unix`机器上支持的所有信号,可以执行`kill -l`命令。 12 | 13 | 如果你在无权限的情况下给一个进程发送信号,`kill(1)`并不会执行,且会返回类似如下的错误提示: 14 | ```shell 15 | $ kill 1210 16 | -bash: kill: (1210) - Operation not permitted 17 | 18 | ``` -------------------------------------------------------------------------------- /eBook/chapter8/08.15.md: -------------------------------------------------------------------------------- 1 | #**`Unix`管道编程** 2 | 3 | 根据`Unix`原理,`Unix`命令行实用程序应该仅且仅执行一个任务!在实践中,这意味着,与其开发执行大量任务的大型实用程序,不如开发多个较小的程序,这些程序组合在一起执行所需的工作。两个或多个`Unix`命令行实用程序通信的最常见方式是使用管道。在`Unix`管道中,一个命令行实用程序的输出是另一个命令行实用程序的输入。此过程可能涉及两个以上的程序!`Unix`管道的标识是字符`|`。 4 | 5 | 管道有两个严重的限制:第一,它们通常是单向通信;第二,它们只能在具有相同祖先的进程之间使用。`Unix`管道实现背后的理念是,如果没有要处理的文件,那么应该等待从标准输入中获取输入。同样,如果不要求将输出保存到文件中,则应将输出写入标准输出,以便用户查看或由其他程序处理。 6 | 7 | 在第一节`Go与操作系统`中,你学习了如何从标准输入中读取,以及如何写入到标准输出。如果你对这两个操作仍有疑问,最好花点时间复习下代码`stdOUT.go`和`stdIN.go`。 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /eBook/chapter8/08.17.md: -------------------------------------------------------------------------------- 1 | #**使用`ePBF`** 2 | 3 | `eBPF`是增强的伯克利包过滤器,它是一个内核的虚拟机,集成到`Linux`内核中,可用于`Linux`跟踪。为了能够使用`eBPF`,需要使用`CONFIG_BPF_SYSCALL`选项编译内核,该选项在`Ubuntu Linux`上自动激活。 4 | 5 | > *`eBPF`在内核版本相对较新的`Linux`机器上工作,但不在`macOS`或`Mac OS X`机器上工作。* 6 | 7 | 你可以在`https://github.com/iovisor/bcc`上了解更多关于`eBPF`的信息,在`https://kinvolk.io/blog/2016/11/introducing-gobpf---using-ebpf-from-go/ `上了解`eBPF`和`Go`。`gobpf`包可在`https://github.com/iovisor/gobpf/`上找到。 8 | 9 | 不幸的是,对`eBPF`和`Go`的进一步讨论超出了本书的范围。 -------------------------------------------------------------------------------- /eBook/chapter8/08.20.md: -------------------------------------------------------------------------------- 1 | #**`User ID`和`group ID`** 2 | 3 | 在本章的最后一节中,你将学习如何查找当前用户的用户`ID`以及当前用户所属的组`ID`。用户`ID`和组`ID`都是保存在`UNIX`系统文件中的正整数。 4 | 5 | 程序名为`ids.go`,分为两部分。第一部分代码如下: 6 | 7 | ```go 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | "os" 13 | "os/user" 14 | ) 15 | 16 | func main() { 17 | fmt.Println("User id:", os.Getuid()) 18 | ``` 19 | 20 | 查找当前用户的用户`ID`与调用`os.Getuid()`函数一样简单。 21 | 22 | `ids.go`第二部分代码如下: 23 | 24 | ```go 25 | var u *user.User 26 | u, _ = user.Current() 27 | fmt.Print("Group ids: ") 28 | groupIDs, _ := u.GroupIds() 29 | for _, i := range groupIDs { 30 | fmt.Print(i, " ") 31 | } 32 | fmt.Println() 33 | } 34 | ``` 35 | 36 | 另一方面,查找用户所属的组`ID`是一项更棘手的任务。 37 | 38 | 执行`ids.go`输出如下: 39 | 40 | ```shell 41 | $ go run ids.go 42 | User id: 501 43 | Group ids: 20 701 12 61 79 80 81 98 33 100 204 250 395 398 399 44 | ``` 45 | 46 | -------------------------------------------------------------------------------- /eBook/chapter8/08.21.md: -------------------------------------------------------------------------------- 1 | #**其他资源** 2 | 3 | 你会发现如下`Web`资源非常有用: 4 | 5 | + `io`包文档可以参考`https://golang.org/pkg/io/ `。 6 | 7 | * 通过访问`ts`官网`https://github.com/Arafatk/glot`,可以了解更多关于`Glot`绘图库的信息。 8 | 9 | * 访问`https://golang.org/pkg/encoding/binary/ `了解更多关于编码/二进制标准包的信息。 10 | 11 | * 访问`https://golang.org/pkg/encoding/gob/`获取`encoding/gob`包的文档 12 | 13 | * 访问`http://www.brendangregg.com/ebpf.html `学习`eBPF`。你也可以观看视频`https://www.youtube.com/watch?v=JRFNIKUROPE and https://www.youtube.com/watch? 14 | v=w8nFRoFJ6EQ `。 15 | 16 | * 你可以在很多地方学习`Endianness`,如`https://en.wikipedia.org/wiki/Endianness`。 17 | 18 | * 访问`https://golang.org/pkg/flag/`查看`flag`包的文档。 19 | 20 | -------------------------------------------------------------------------------- /eBook/chapter8/08.22.md: -------------------------------------------------------------------------------- 1 | #**练习** 2 | 3 | * 编写一个`Go`程序,它有三个参数:一个文本文件的名称,和两个字符串。程序应使用第二个字符串替换文件中每次出现的第一个字符串。由于安全原因,最终输出将打印在屏幕上,也就是说原始文本文件将保持完整。 4 | * 使用`encoding/gob`包序列化和反序列化`Go`映射以及结构体的切片。 5 | * 创建一个`Go`程序,处理你选择的任意三个信号。 6 | * 在`Go`中创建一个程序,将文本文件中的所有制表符替换为命令行中指定数量的空格符。同样,输出将打印在屏幕上。 7 | * 开发一个程序,逐行读取文本文件并使用`strings.TrimSpace()`函数从每一行中删除空格字符。 8 | * 修改`kvSaveLoad.go`以支持单个命令行参数,该参数是个文件名,用于加载和保存数据。 9 | * 你能创建`wc(1)`程序的`Go`版本吗?看一下`wc(1)`的手册页,找到有关命令行选项的信息支持。 10 | * 修改`goFind.go`的代码只打印普通文件。这意味着它不应该打印目录、套接字和符号链接。 11 | * 你能编写一个使用`Glot`来绘制函数的程序吗? 12 | * 修改`traceSyscall.go`以便在跟踪时显示每个系统调用。 13 | * 修改`cat.go`仅支持`io.Copy(os.Stdout,f)`,直接复制文件的内容,而不是扫描所有的内容。 14 | * 你还可以使用`bufio.Newscanner()`和`bufio.ScanWords`逐字逐句地读一行。了解如何创建一个新版本的`byWord.go`程序。 -------------------------------------------------------------------------------- /eBook/chapter8/08.23.md: -------------------------------------------------------------------------------- 1 | #**总结** 2 | 3 | 本章谈到了很多有趣的话题,包括阅读文件、写入文件、以及使用`flag`包。然而,有很多与系统编程相关的话题未在本章提及,如使用目录、复制、删除和重命名文件、处理`Unix`用户、组和`Unix`进程、使用环境变量如`PATH`、改变`Unix`文件权限、生成稀疏文件、读取和保存`JSON`数据、锁定和创建文件,使用和旋转日志文件,以及`os.Stat()`调用返回的结构中的信息。 4 | 5 | -------------------------------------------------------------------------------- /eBook/chapter8/08.3.1.md: -------------------------------------------------------------------------------- 1 | **缓冲和无缓冲的文件输入和输出** 2 | 3 | 缓冲文件输入和输出发生在读取或写入数据之前有一个临时存储数据的缓冲区。因此,你可以一次读取多个字节,而不是逐字节地读取一个文件。你将它放在一个缓冲区中,等待调用者以所需的方式读取它。非缓冲文件输入和输出发生在实际读取或写入数据之前没有临时存储数据的缓冲区时。 4 | 5 | 你可能会问的下一个问题是,如何决定何时使用缓冲文件输入和输出,以及何时使用非缓冲文件输入和输出。在处理关键数据时,非缓冲文件输入和输出通常是更好的选择,因为缓冲读取可能导致过期的数据,而缓冲写入可能在计算机电源中断时导致数据丢失。然而,大多数时候,这个问题没有明确的答案。这意味着你可以使用任何使任务更容易实现的工具。 6 | 7 | -------------------------------------------------------------------------------- /eBook/chapter8/08.3.md: -------------------------------------------------------------------------------- 1 | # **io.Reader和io.Writer接口** 2 | 3 | 如前所述,实现`io.Reader`接口需要实现`Read()`方法,`io.Writer()`接口需要实现`Write()`方法。这两个接口在`Go`中非常常见,我们将在稍后使用它们。 4 | 5 | -------------------------------------------------------------------------------- /eBook/chapter8/08.4.md: -------------------------------------------------------------------------------- 1 | # **bufio包** 2 | 3 | 顾名思义,`bufio`包是关于缓冲输入输出的。但是,`bufio`包在内部仍然使用`io.Reader`和`io.Writer`对象,它封装这些对象分别创建`bufio.Reader`和`bufio.Writer`对象。 4 | 5 | 下一节中,我们会看到,`bufio`包非常适合读取文本文件。 6 | 7 | -------------------------------------------------------------------------------- /eBook/chapter8/08.5.md: -------------------------------------------------------------------------------- 1 | # **读取文本文件** 2 | 3 | 文本文件是`Unix`系统中最常见的一种文件。在本节中,你将学习如何以三种方式读取文本文件:逐行读取、逐词读取、逐字符读取。如你所见,逐行读取是访问文本文件的最简单方法,而逐词读取是最困难的方法。 4 | 5 | 如果你仔细观察`byLine.go`、`byWord.go`、`byCharacter.go`程序,你会发现它们的`Go`代码有许多相似之处。首先,它们都是逐行读取输入文件。其次,除了`main()`函数的`for`循环中调用的函数不同之外,这三个实用程序都具有相同的`main()`函数。最后,除了函数的实现部分不同之外,处理输入文本文件的三个函数几乎是相同的。 6 | 7 | -------------------------------------------------------------------------------- /eBook/chapter8/08.7.md: -------------------------------------------------------------------------------- 1 | #**为什么我们使用二进制格式** 2 | 3 | 在前一节中,`readSize.go`程序演示了如何逐字节读取文件,这是一种应用于二进制文件的技术。那么,你可能会问,既然文本格式更容易理解,为什么要读取二进制格式的数据呢?主要原因是节省空间。假设你想将数字`20`作为字符串存储到文件中。很容易理解,使用`ASCII`字符存储`20`需要两个字节,一个用于存储`2`,另一个用于存储`0`。以二进制格式存储`20`只需要一个字节,因为`20`可以用二进制表示为`00010100`,也可以用十六进制表示为`0x14`。 4 | 5 | 在处理少量数据时,这种差异可能看起来微不足道,但在处理应用程序(如数据库服务器)中的数据时,这种差异可能非常显著。 6 | 7 | -------------------------------------------------------------------------------- /eBook/chapter9/09.0.md: -------------------------------------------------------------------------------- 1 | # **GO并发-协程,通道和管道** 2 | 3 | 上一章我们讨论了Go系统编程,包括Go函数和与操作系统通信的技术。前一章未涉及的两个系统编程领域是并发编程以及创建和管理多个线程。这两个主题将在本章和下一章中讨论。 4 | 5 | GO提供了自己独特而新颖的方式来实现并发,这就是协程和通道。协程Goroutine是Go程序中可独立执行的最小实体单元,而通道Channel是Goroutine间并发且有效地获取数据的方式,从而允许goroutine具有引用点并相互通信。Go中的所有内容都是使用goroutines执行的,这是完全合理的,因为Go是一种并发编程语言。因此,当Go程序开始执行时,它的单个goroutine调用main()函数,该函数执行实际的程序。 6 | 7 | 本章的主要内容如下: 8 | 9 | * 进程,线程和Go协程之间的区别 10 | * Go调度器 11 | * 并发与并行 12 | * 创建Go协程 13 | * 创建通道 14 | * 从通道读取或接收数据 15 | * 往通道里写或发送数据 16 | * 创建管道 17 | * 等待你的Go协程结束 -------------------------------------------------------------------------------- /eBook/chapter9/09.1.1.md: -------------------------------------------------------------------------------- 1 | # **Go调度器** 2 | 3 | Unix内核调度程序负责程序线程的执行。另一方面,Go运行时也有自己的调度程序,它使用称为 m:n 的调度技术负责执行Goroutine,使用多路复用使n个操作系统线程执行m个Goroutine。Go调度程序是Go的组件,负责Go程序中Goroutine的执行方式和执行顺序。这使得Go调度程序成为Go编程语言中非常重要的一部分,因为Go程序中很多都是作为Goroutine执行的。 4 | 5 | 需要留意的是,由于Go调度程序仅处理单个程序的Goroutine,因此其操作比内核调度程序的操作更简单,更轻量,更快。 -------------------------------------------------------------------------------- /eBook/chapter9/09.1.2.md: -------------------------------------------------------------------------------- 1 | # **并发与并行** 2 | 3 | 有一个非常普遍的误解,认为并发与并行是一回事 - 其实不然!并行是同时执行某种类型的多个实体,而并发是构建组件的一种方式,以便它们可以在可能的情况下独立执行。 4 | 5 | 当您的操作系统和硬件允许时,只有当您并发地构建软件组件时,才能以并行地方式安全执行。早在CPU拥有多个内核且计算机拥有大量RAM之前,Erlang编程语言就有过类似的实践。 6 | 7 | 在有效的并发设计中,添加并发实体会使整个系统运行得更快,因为可以并行运行更多内容。因此,期望的并行性来自更好的并发表达和问题的实现。开发人员负责在系统的设计阶段考虑并发性,并从系统组件的潜在并行执行中受益。因此,开发人员不应该考虑并行性,而应该将程序分解为独立的组件,以便于通过组合来解决前面提到的问题。 8 | 9 | 即使您无法在Unix机器上并行运行功能,有效的并发设计仍可以改进程序的设计和可维护性。换句话说,并发性优于并行性! -------------------------------------------------------------------------------- /eBook/chapter9/09.1.md: -------------------------------------------------------------------------------- 1 | # **关于进程,线程和Go协程** 2 | 3 | 进程是包含计算机指令,用户数据和系统数据的程序执行环境,以及包含其运行时获得的其他类型资源。而程序是一个文件,其中包含用于初始化进程的指令和用户数据部分的指令和数据。 4 | 5 | 线程相对于进程是更加小巧而轻量的实体,线程由进程创建且包含自己的控制流和栈,线程和进程的区别在于:进程是正在运行的二进制文件,而线程是进程的子集。 6 | 7 | Goroutine是Go程序并发执行的最小单元,因为Goroutine不是像Unix进程那样是自治的实体,Goroutine生活在Unix进程的线程中。Goroutine的主要优点是非常轻巧,运行成千上万或几十万都没有问题。 8 | 9 | 总结一下,Goroutine比线程更轻量,而线程比进程更轻量。实际上,一个进程可以有多个线程以及许多Goroutine,而Goroutine需要一个进程的环境才能存在。因此,为了创建一个Goroutine,你需要有一个进程且这个进程至少有一个线程--Unix负责进程和线程管理,而Go工程师只需要处理Goroutine,这极大的降低了开发的成本。 10 | 11 | 到现在为止,你知道了关于进程,线程和Goroutine的基本知识,下一小节我们聊聊Go调度器。 -------------------------------------------------------------------------------- /eBook/chapter9/09.2.1.md: -------------------------------------------------------------------------------- 1 | # **创建一个Goroutine** 2 | 3 | 在本小节中,您将学习两种创建goroutine的方法。第一种方法是使用常规的函数,而第二种方法是使用匿名函数 - 这两种方法其实是类似的。 4 | 5 | 本小节所展示的程序文件为simple.go,它分为三个部分。 6 | 7 | simple.go的第一部分代码如下: 8 | 9 | > ``` 10 | > package main 11 | > 12 | > import ( 13 | > "fmt" 14 | > "time" 15 | > ) 16 | > 17 | > func function() { 18 | > for i := 0; i < 10; i++ { 19 | > fmt.Print(i) 20 | > } 21 | > fmt.Println() 22 | > } 23 | > ``` 24 | 25 | 除了import包之外,上面的代码定义了一个名为function()的函数,该函数将在下面的代码内使用。 26 | 27 | 接下来是simple.go的第二部分代码: 28 | 29 | > ``` 30 | > func main() { 31 | > go function() 32 | >``` 33 | 34 | 上面的代码启用一个新的Goroutine来运行function()函数。然后主程序会继续执行,而function()函数开始在后台运行。 35 | 36 | simple.go的最后一部分代码如下: 37 | 38 | > ``` 39 | > go func() { 40 | > for i := 10; i < 20; i++ { 41 | > fmt.Print(i, " ") 42 | > } 43 | > }() 44 | > 45 | > time.Sleep(1 * time.Second) 46 | > } 47 | > ``` 48 | 49 | 如上所示,您也可以使用匿名函数创建Goroutine。此方法适合相对较小的功能。如果函数体有大量代码,最好使用go关键字创建常规函数来执行它。 50 | 51 | 正如您将在下一节中看到的,您可以按照自己的方式创建多个Goroutine,当然也可以使用for循环。 52 | 53 | 执行simple.go两次后的输出如下: 54 | 55 | > ``` 56 | > $ go run simple.go 57 | > 10 11 12 13 14 0123456789 58 | > 15 16 17 18 19 59 | > 60 | > $ go run simple.go 61 | > 10 11 12 13 14 15 16 17 18 19 0123456789 62 | > ``` 63 | 64 | 尽管您想要的程序是对于同一个输入有相同的输出,但从上面的执行结果来看,两次的输出并不是相同的。我们可以总结一下:在不做额外工作的自然情况下我们是无法控制Goroutine的执行顺序的,如果要控制它,我们需要编写额外的代码。在下一章我们将学习到这部分内容。 65 | -------------------------------------------------------------------------------- /eBook/chapter9/09.2.md: -------------------------------------------------------------------------------- 1 | # **Goroutines** 2 | 3 | 在Go语言中使用go关键字后跟函数名称或定义完整的匿名函数即可开启一个新的Goroutine,使用go关键字调用函数后会立即返回,该函数在后台作为Goroutine运行,程序的其余部分继续执行 4 | 5 | 但是,如上所述,您无法控制您的Goroutine的执行顺序,因为这取决于操作系统的调度程序,Go调度程序以及操作系统的负载。 -------------------------------------------------------------------------------- /eBook/chapter9/09.3.1.md: -------------------------------------------------------------------------------- 1 | # **当Add()和Done()的数量不匹配时会发生什么?** 2 | 3 | 当sync.Add()和sync.Done()调用的数量相等时,程序会正常运行。但是,本节将告诉您当调用数量不一致时会发生什么。 4 | 5 | 假如我们执行sync.Add()的次数大于执行sync.Done()的次数,这种情况下,通过在第一个fmt.Printf(“%#v \ n”,waitGroup)之前添加waitGroup.Add(1)语句,然后执行go run的输出如下: 6 | 7 | ``` 8 | $ go run syncGo.go Going to create 20 goroutines. sync.WaitGroup{noCopy:sync.noCopy{}, state1:[12]uint8{0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, sema:0x0} sync.WaitGroup{noCopy:sync.noCopy{}, ... 9 | ``` -------------------------------------------------------------------------------- /eBook/chapter9/09.4.1.md: -------------------------------------------------------------------------------- 1 | # 通道的写入 2 | 3 | 这小节的代码将教您怎样往通道写入数据。写 `x` 值到 `c` 通道如同 `c <- x` 一样容易。这个箭头表示值的方向,只要 `x` 和 `c` 是相同的类型用这个表达式就不会有问题。这节的示例保存在 `writeCh.go` 中,并分三部分介绍。 4 | 5 | `writeCh.go` 的第一段代码如下: 6 | 7 | ```go 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | "time" 13 | ) 14 | 15 | func writeToChannel(c chan int, x int) { 16 | fmt.Println(x) 17 | c <- x 18 | close(c) 19 | fmt.Println(x) 20 | } 21 | ``` 22 | 23 | `chan` 关键字是用于声明函数参数 `c` 是一个通道,并且伴随通道(`int`) 类型。`c <-x` 表达式允许您写 `x` 值到 `c` 通道,并用`close()` 函数关闭这个通道;那样就不会再和它通信了。 24 | 25 | `writeCh.go` 的第二部分代码如下: 26 | 27 | ```go 28 | func main() { 29 | c := make(chan int) 30 | ``` 31 | 32 | 上面的代码定义了一个名为 `c` 的通道变量,第一次在这章使用 `make()` 函数和 `chan` 关键字。所有的通道都有一个指定的类型。 33 | 34 | `writeCh.go` 的其余代码如下: 35 | 36 | ```go 37 | go writeToChannel(c, 10) 38 | time.Sleep(1 * time.Second) 39 | } 40 | ``` 41 | 42 | 这里以 goroutine 的方式执行 `writeToChannel()` 函数并调用 `time.Sleep()` 来给 `writeToChannel()` 函数足够的时间来执行。 43 | 44 | 执行 `writeCh.go` 将产生如下输出: 45 | 46 | ```shell 47 | $go run writeCh.go 48 | 10 49 | ``` 50 | 51 | 奇怪的是 `writeToChannel()` 函数只打印了一次给定的值。这是由于第二个 `fmt.Println(x)` 表达式没有执行。一旦您理解了通道的工作原理,这个原因就非常简单了:`c <- x` 表达式阻塞了 `writeChannel()` 函数下面的执行,因为没人读取 `c` 通道内写入的值。所以,当 `time.Sleep(1 * time.Second)` 表达式结束的时候,程序没有等待 `writeChannel()` 就结束了。 52 | 53 | 下节将说明怎么从通道读数据。 -------------------------------------------------------------------------------- /eBook/chapter9/09.4.2.md: -------------------------------------------------------------------------------- 1 | # **从通道接收数据** 2 | 3 | 这小节,您将了解到如何从通道读取数据。您可以执行 `<-c` 从名为 `c` 的通道读取一个值。如此,箭头方向是从通道到外部。 4 | 5 | 我将使用名为 `readCh.go` 的程序帮您理解怎样从通道读取数据,并它分为三部分介绍。 6 | 7 | `readCh.go` 的第一段代码如下: 8 | 9 | ```go 10 | package main 11 | 12 | import ( 13 | "fmt" 14 | "time" 15 | ) 16 | 17 | func writeToChannel(c chan int, x int) { 18 | fmt.Println("l", x) 19 | c <- x 20 | close(c) 21 | fmt.Println("2", x) 22 | } 23 | ``` 24 | 25 | `writeToChannel()` 函数的实现与之前一样。 26 | 27 | `readCh.go` 的第二部分如下: 28 | 29 | ```go 30 | func main() { 31 | c := make(chan int) 32 | go writeToChannel(c, 10) 33 | time.Sleep(1 * time.Second) 34 | fmt.Println("Read:", <-c) 35 | time.Sleep(1 * time.Second) 36 | ``` 37 | 38 | 上面的代码,使用 `<-c` 语法从 `c` 通道读取数据。如果您想要保存数据到名为 `k` 的变量而不只是打印它的话,您可以使用 `k := <-c` 表达式。第二个 `time.Sleep(1 * time.Second)` 语句给您时间来读取通道数据。 39 | 40 | `readCh.go` 的最后一段代码如下: 41 | 42 | ```go 43 | _, ok := <-c 44 | if ok { 45 | fmt.Println("Channel is open!") 46 | }else { 47 | fmt.Println("Channel is closed!") 48 | } 49 | } 50 | ``` 51 | 52 | 从上面的代码,您能看到一个判断一个通道是打开还是关闭的技巧。当通道关闭时,当前代码运行的还不错。但是,如果通道被打开,这里的代码就会丢弃从通道读取的值,因为在 `_, ok := <-c` 语句中使用了 `_` 字符。如果您也想在通道打开时读取通道的值,就使用一个有意义的变量名代替 `_`。 53 | 54 | 执行 `readCh.go` 产生如下输出: 55 | 56 | ```shell 57 | $go run readCh.go 58 | 1 10 59 | Read: 10 60 | Channel is closed! 61 | $go run readCh.go 62 | 1 10 63 | 2 10 64 | Read: 10 65 | Channel is closed! 66 | ``` 67 | 68 | 尽管输出不确定,但 `writeToChannel()` 函数的两个 `fmt->Println(x)` 表达式都被执行了,因为当您从通道读取数据时,它就被解除阻塞了。 -------------------------------------------------------------------------------- /eBook/chapter9/09.4.3.md: -------------------------------------------------------------------------------- 1 | # **通道作为函数参数传递** 2 | 3 | 虽然 `readCh.go` 和 `writeCh.go` 没有使用这一功能,但 Go 允许您在把通道作为函数的参数时指定它的方向;那就是它是否用于读取或写入数据。通道有两种类型,**无向通道**和默认的双向通道。 4 | 5 | 查看下面两个函数代码: 6 | 7 | ```go 8 | func f1(c chan int, x int) { 9 | fmt.Println(x) 10 | c <- x 11 | } 12 | 13 | func f2(c chan<- int, x int){ 14 | fmt.Println(x) 15 | c <- x 16 | } 17 | ``` 18 | 19 | 虽然两个函数实现了相同的功能,但它们的定义略有不同。`f2()` 函数的 `chan` 关键字右侧有个 `<-` 符号。这说明过 `c` 通道只能用于写数据。如果 Go 代码试图从一个只读通道(只发通道)读取数据的话,Go 编译器就会产生如下错误信息: 20 | 21 | ```shell 22 | # command-line-arguments 23 | a.go:19:11: invalid operation: range in (recevie from send-only type chan<- int) 24 | ``` 25 | 26 | 同样,有下面的函数定义: 27 | 28 | ```go 29 | func f1(out chan int64, in chan int64) { 30 | fmt.Println(x) 31 | c <- x 32 | } 33 | 34 | func f2(out chan<- int64, in <-chan int64) { 35 | fmt.Println(x) 36 | c <- x 37 | } 38 | ``` 39 | 40 | `f2` 定义含有名为 `in` 的只读通道和 `out` 的只写通道。如果您试图向函数的一个只读通道(只收通道)参数写数据和关闭它时,会得到如下错误信息: 41 | 42 | ```shell 43 | # command-line-arguments 44 | a.go:13:7: invalid operation: out <- i(send to receive-only type <-chan int) 45 | a.go:15:7: invalid operation: close(out)(cannot close receive-only channel) 46 | ``` 47 | -------------------------------------------------------------------------------- /eBook/chapter9/09.4.md: -------------------------------------------------------------------------------- 1 | # **Channel(通道)** 2 | 3 | 通道是Go提供的一种通信机制,允许Goroutines之间进行数据传输。但也有一些明确的规则,首先,每个通道只允许交换指定类型的数据,也称为通道的元素类型,其次,要使通道正常运行,还需要保证通道有数据接收方。使用chan关键字即可声明一个新通道,且可以使用close()函数来关闭通道。 4 | 5 | 最后,有一个非常重要的细节:当您使用通道作为函数参数时,您可以指定其方向; 也就是说,该通道是用于发送数据或是接收数据。 -------------------------------------------------------------------------------- /eBook/chapter9/09.6.md: -------------------------------------------------------------------------------- 1 | # **其他学习资源** 2 | 3 | 访问以下有用资源: 4 | 5 | + `sync` 包的文档页在[https://golang.org/pkg/sync](https://golang.org/pkg/sync)。 6 | + 还是 `sync` 包的文档页。关注 `sync.Mutext` 和 `sync.RWMutex` 类型,它们将在下章出现。 -------------------------------------------------------------------------------- /eBook/chapter9/09.7.md: -------------------------------------------------------------------------------- 1 | # **练习题** 2 | 3 | + 创建一个管道来读取文本文件,找到每个文件里给定短语的出现次数,并计算所有文件中该短语出现的总数。 4 | + 创建一个管道来计算给定范围的所有自然数的平方和。 5 | + 从 `simple.go` 程序总移除 `time.Sleep(1 * time.Second)` 表达式,看看会发生什么。为什么? 6 | + 修改 `pipeling.go` 的代码来创建一个管道,用五个函数和适当的通道。 7 | + 修改 `pipleline.go` 代码来找出当您忘记关闭 `first()` 函数中的 `out` 通道时会发生什么。 -------------------------------------------------------------------------------- /eBook/chapter9/09.8.md: -------------------------------------------------------------------------------- 1 | # 本章小结 2 | 3 | 在这章里,您了解到了许多 Go 的独特功能,包括 goroutines,通道和管道。另外,您学到了使用 `sync` 包提供的功能来给 goroutines 提供足够的时间去完成它们的任务。最后,您了解到了通道可以作为函数的参数。这允许开发者创建数据流管道。 4 | 5 | 下章将通过介绍 `select` 关键字来继续讨论 Go 的并发。这个关键字可以让通道执行许多有趣的任务,我想您会真正的被它的强大所震惊。之后,您将看到两个技巧,用于处理一个或多个因为某些原因而超时的 goroutines。然后,您将了解空通道,信号通道,通道的通道和缓冲通道,还有 `context` 包。 6 | 7 | 在下章您也会了解到**共享内存**,它是同一个 Unix 进程中的线程间共享信息的传统方式,它也适用于 goroutines。不过,共享内存在 Go 开发者中并不流行,因为 Go 提供了更好,更安全和更快速的方法给 goroutines 来交换数据。 -------------------------------------------------------------------------------- /eBook/examples/chapter10/bufChannel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | numbers := make(chan int, 5) 9 | counter := 10 10 | for i := 0; i < counter; i++ { 11 | select { 12 | case numbers <- i: 13 | default: 14 | fmt.Println("Not enough space for", i) 15 | } 16 | } 17 | for i := 0; i < counter+5; i++ { 18 | select { 19 | case num := <-numbers: 20 | fmt.Println(num) 21 | default: 22 | fmt.Println("Nothing more to be done!") 23 | break 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /eBook/examples/chapter10/chSquare.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | "time" 8 | ) 9 | 10 | var times int 11 | 12 | func f1(cc chan chan int, f chan bool) { 13 | c := make(chan int) 14 | cc <- c 15 | defer close(c) 16 | 17 | sum := 0 18 | select { 19 | case x := <-c: 20 | for i := 0; i <= x; i++ { 21 | sum = sum + i 22 | } 23 | c <- sum 24 | case <-f: 25 | return 26 | } 27 | } 28 | 29 | func main() { 30 | arguments := os.Args 31 | if len(arguments) != 2 { 32 | fmt.Println("Need just one integer argument!") 33 | return 34 | } 35 | 36 | times, err := strconv.Atoi(arguments[1]) 37 | if err != nil { 38 | fmt.Println(err) 39 | return 40 | } 41 | 42 | cc := make(chan chan int) 43 | 44 | for i := 1; i < times+1; i++ { 45 | f := make(chan bool) 46 | go f1(cc, f) 47 | ch := <-cc 48 | ch <- i 49 | for sum := range ch { 50 | fmt.Print("Sum(", i, ")=", sum) 51 | } 52 | fmt.Println() 53 | time.Sleep(time.Second) 54 | close(f) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /eBook/examples/chapter10/closeNilChannel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | var c chan string 5 | close(c) 6 | } 7 | -------------------------------------------------------------------------------- /eBook/examples/chapter10/defineOrder.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func A(a, b chan struct{}) { 9 | <-a 10 | fmt.Println("A()!") 11 | time.Sleep(time.Second) 12 | close(b) 13 | } 14 | 15 | func B(a, b chan struct{}) { 16 | <-a 17 | fmt.Println("B()!") 18 | close(b) 19 | } 20 | 21 | func C(a chan struct{}) { 22 | <-a 23 | fmt.Println("C()!") 24 | } 25 | 26 | func main() { 27 | x := make(chan struct{}) 28 | y := make(chan struct{}) 29 | z := make(chan struct{}) 30 | 31 | go C(z) 32 | go A(x, y) 33 | go C(z) 34 | go B(y, z) 35 | go C(z) 36 | 37 | close(x) 38 | time.Sleep(3 * time.Second) 39 | } 40 | -------------------------------------------------------------------------------- /eBook/examples/chapter10/forgetMutex.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | var m sync.Mutex 9 | 10 | func function() { 11 | m.Lock() 12 | fmt.Println("Locked!") 13 | } 14 | 15 | func main() { 16 | var w sync.WaitGroup 17 | 18 | go func() { 19 | defer w.Done() 20 | function() 21 | }() 22 | w.Add(1) 23 | 24 | go func() { 25 | defer w.Done() 26 | function() 27 | }() 28 | w.Add(1) 29 | 30 | w.Wait() 31 | } 32 | -------------------------------------------------------------------------------- /eBook/examples/chapter10/maxprocs.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | func getGOMAXPROCS() int { 9 | return runtime.GOMAXPROCS(0) 10 | } 11 | 12 | func main() { 13 | fmt.Printf("GOMAXPROCS:%d\n", getGOMAXPROCS()) 14 | } 15 | -------------------------------------------------------------------------------- /eBook/examples/chapter10/monitor.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "os" 7 | "strconv" 8 | "sync" 9 | "time" 10 | ) 11 | 12 | var readValue = make(chan int) 13 | var writeValue = make(chan int) 14 | 15 | func set(newValue int) { 16 | writeValue <- newValue 17 | } 18 | 19 | func read() int { 20 | return <-readValue 21 | } 22 | 23 | func monitor() { 24 | var value int 25 | 26 | for { 27 | select { 28 | case newValue := <-writeValue: 29 | value = newValue 30 | fmt.Printf("%d", value) 31 | case readValue <- value: 32 | } 33 | } 34 | } 35 | 36 | func main() { 37 | if len(os.Args) != 2 { 38 | fmt.Println("Please give an integer!") 39 | return 40 | } 41 | n, err := strconv.Atoi(os.Args[1]) 42 | if err != nil { 43 | fmt.Println(err) 44 | return 45 | } 46 | 47 | fmt.Printf("Going to create %d random numbers.\n", n) 48 | rand.Seed(time.Now().Unix()) 49 | go monitor() 50 | var w sync.WaitGroup 51 | for r := 0; r < n; r++ { 52 | w.Add(1) 53 | go func() { 54 | defer w.Done() 55 | set(rand.Intn(10 * n)) 56 | }() 57 | } 58 | w.Wait() 59 | fmt.Printf("\nLast value: %d\n", read()) 60 | } 61 | -------------------------------------------------------------------------------- /eBook/examples/chapter10/mutex.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | var ( 12 | m sync.Mutex 13 | v1 int 14 | ) 15 | 16 | func change(i int) { 17 | m.Lock() 18 | time.Sleep(time.Second) 19 | v1 = v1 + 1 20 | if v1%10 == 0 { 21 | v1 = v1 - 10*i 22 | } 23 | m.Unlock() 24 | } 25 | 26 | func read() int { 27 | m.Lock() 28 | a := v1 29 | m.Unlock() 30 | return a 31 | } 32 | 33 | func main() { 34 | if len(os.Args) != 2 { 35 | fmt.Println("Please give me an integer!") 36 | return 37 | } 38 | 39 | numGR, err := strconv.Atoi(os.Args[1]) 40 | if err != nil { 41 | fmt.Println(err) 42 | return 43 | } 44 | var waitGroup sync.WaitGroup 45 | 46 | fmt.Printf("%d ", read()) 47 | for i := 0; i < numGR; i++ { 48 | waitGroup.Add(1) 49 | go func(i int) { 50 | defer waitGroup.Done() 51 | change(i) 52 | fmt.Printf("-> %d", read()) 53 | }(i) 54 | } 55 | 56 | waitGroup.Wait() 57 | fmt.Printf("-> %d\n", read()) 58 | } 59 | -------------------------------------------------------------------------------- /eBook/examples/chapter10/nilChannel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | func add(c chan int) { 10 | sum := 0 11 | t := time.NewTimer(time.Second) 12 | for { 13 | select { 14 | case input := <-c: 15 | sum = sum + input 16 | case <-t.c: 17 | c = nil 18 | fmt.Println(sum) 19 | } 20 | } 21 | } 22 | 23 | func send(c chan int) { 24 | for { 25 | c <- rand.Intn(10) 26 | } 27 | } 28 | 29 | func main() { 30 | c := make(chan int) 31 | go add(c) 32 | go send(c) 33 | time.Sleep(3 * time.Second) 34 | } 35 | -------------------------------------------------------------------------------- /eBook/examples/chapter10/noRaceC.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | "sync" 8 | ) 9 | 10 | func main() { 11 | arguments := os.Args 12 | if len(arguments) != 2 { 13 | fmt.Println("Give me a natural number!") 14 | os.Exit(1) 15 | } 16 | numGR, err := srconv.Atoi(os.Args[1]) 17 | if err != nil { 18 | fmt.Println(err) 19 | return 20 | } 21 | 22 | var waitGroup syncWaitGroup 23 | var i int 24 | 25 | k := make(map[int]int) 26 | k[1] = 12 27 | 28 | for i = 0; i < numGR; i++ { 29 | waitGroup.Add(1) 30 | go runc(j int) { 31 | defer waitGroup.Done() 32 | aMutex.Lock() 33 | k[j] = j 34 | aMutex.Unlock() 35 | }(i) 36 | } 37 | 38 | waitGroup.Wait() 39 | k[2] = 10 40 | fmt.Printf("k = %#v\n", k) 41 | } -------------------------------------------------------------------------------- /eBook/examples/chapter10/raceC.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | "sync" 8 | ) 9 | 10 | func main() { 11 | arguments := os.Args 12 | if len(arguments) != 2 { 13 | fmt.Println("Give me a natural number!") 14 | os.Exit(1) 15 | } 16 | numberGR, err := strconv.Atoi(os.Args[1]) 17 | if err != nil { 18 | fmt.Println(err) 19 | return 20 | } 21 | 22 | var waitGroup sync.WaitGroup 23 | var i int 24 | 25 | k := make(map[int]int) 26 | k[1] = 12 27 | for i = 0; i < numGR; i++ { 28 | waitGroup.Add(1) 29 | go func() { 30 | defer waitGroup.Done() 31 | k[i] = i 32 | }() 33 | } 34 | 35 | k[2] = 10 36 | waitGroup.Wait() 37 | fmt.Println("k = %v\n", k) 38 | } 39 | -------------------------------------------------------------------------------- /eBook/examples/chapter10/rwMutex.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | var Password = secret{password: "myPassword"} 11 | 12 | type secret struct { 13 | RWM sync.RWMutex 14 | M sync.Mutex 15 | password string 16 | } 17 | 18 | func Change(c *secret, pass string) { 19 | c.RWM.Lock() 20 | fmt.Println("LChange") 21 | time.Sleep(10 * time.Second) 22 | c.password = pass 23 | c.RWM.Unlock() 24 | } 25 | 26 | func show(c *secret) string { 27 | c.RWM.RLock() 28 | fmt.Println("show") 29 | time.Sleep(3 * time.Second) 30 | defer c.RWM.RUnlock() 31 | return c.password 32 | } 33 | 34 | func showWithLock(c *secret) string { 35 | c.M.Lock() 36 | fmt.Println("showWithLock") 37 | time.Sleep(3 * time.Second) 38 | defer c.M.Unlock() 39 | return c.password 40 | } 41 | 42 | func main() { 43 | var showFunction = func(c *secret) string { return "" } 44 | if len(os.Args) != 2 { 45 | fmt.Println("Using sync.RWMutex!") 46 | showFunction = show 47 | } else { 48 | fmt.Println("Using sync.Mutex!") 49 | showFunction = showWithLock 50 | } 51 | 52 | var waitGroup sync.WaitGroup 53 | fmt.Println("Pass:", showFunction(&Password)) 54 | 55 | for i := 0; i < 15; i++ { 56 | waitGroup.Add(1) 57 | go func() { 58 | defer waitGroup.Done() 59 | fmt.Println("Go Pass:", showFunction(&Password)) 60 | }() 61 | 62 | go func() { 63 | waitGroup.Add(1) 64 | defer waitGroup.Done() 65 | Change(&Password, "123456") 66 | }() 67 | waitGroup.Wait() 68 | fmt.Println("Pass:", showFunction(&Password)) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /eBook/examples/chapter10/select.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "os" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | func gen(min, max int, createNumber chan int, end chan bool) { 12 | for { 13 | select { 14 | case createNumber <- rand.Intn(max-min) + min: 15 | case <-end: 16 | close(end) 17 | return 18 | case <-time.After(4 * time.Second): 19 | fmt.Println("\ntime.After()!") 20 | } 21 | } 22 | } 23 | 24 | func main() { 25 | rand.Seed(time.Now().Unix()) 26 | createNumber := make(chan int) 27 | end := make(chan bool) 28 | 29 | if len(os.Args) != 2 { 30 | fmt.Println("Please give me an integer!") 31 | return 32 | } 33 | 34 | n, _ := strconv.Atoi(os.Args[1]) 35 | fmt.Printf("Going to create %d random numbers.\n", n) 36 | go gen(0, 2*n, createNumber, end) 37 | 38 | for i := 0; i < n; i++ { 39 | fmt.Printf("%d ", <-createNumber) 40 | } 41 | 42 | time.Sleep(5 * time.Second) 43 | fmt.Println("Exting...") 44 | end <- true 45 | } 46 | -------------------------------------------------------------------------------- /eBook/examples/chapter10/slowWWW.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "net/http" 7 | "os" 8 | "time" 9 | ) 10 | 11 | func random(min, max int) int { 12 | return rand.Intn(max-min) + min 13 | } 14 | 15 | func myHandler(w http.ResponseWriter, r *http.Request) { 16 | delay := random(0, 15) 17 | time.Sleep(time.Duration(delay) * time.Second) 18 | 19 | fmt.Fprintf(w, "Servring: %s\n", r.URL.Path) 20 | fmt.Fprintf(w, "Dealy: %d\n", delay) 21 | fmt.Printf("Served: %s\n", r.Host) 22 | } 23 | 24 | func main() { 25 | seed := time.Now().Unix() 26 | rand.Seed(seed) 27 | 28 | PORT := ":8001" 29 | arguments := os.Args 30 | if len(arguments) == 1 { 31 | fmt.Println("Using default port nubmer: ", PORT) 32 | } else { 33 | PORT = ":" + arguments[1] 34 | } 35 | 36 | http.HandleFunc("/", myHandler) 37 | err := http.ListenAndServer(PORT, nil) 38 | if err != nil { 39 | fmt.Println(err) 40 | os.Exit(10) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /eBook/examples/chapter10/timeOut1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | c1 := make(chan string) 10 | go func() { 11 | time.Sleep(time.Second * 3) 12 | c <- "c1 OK" 13 | }() 14 | 15 | select { 16 | case res := <-c1: 17 | fmt.Println(res) 18 | case <-time.After(time.Second * 1): 19 | fmt.Println("timeout c1") 20 | } 21 | 22 | c2 := make(chan string) 23 | go func() { 24 | time.Sleep(3 * time.Second) 25 | c2 <- "c2 OK" 26 | }() 27 | 28 | select { 29 | case res := <-c2: 30 | fmt.Println(res) 31 | case <-time.After(4 * time.Second): 32 | fmt.Println("timeout c2") 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /eBook/examples/chapter10/timeOut2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | func timeout(w *sync.WaitGroup, t time.Duration) bool { 12 | temp := make(chan int) 13 | go func() { 14 | time.Sleep(5 * time.Second) 15 | defer close(temp) 16 | w.Wait() 17 | }() 18 | 19 | select { 20 | case <-temp: 21 | return false 22 | case <-time.After(t): 23 | return true 24 | } 25 | } 26 | 27 | func main() { 28 | arguments := os.Args 29 | if len(arguments) != 2 { 30 | fmt.Println("Need a time duration!") 31 | return 32 | } 33 | 34 | var w sync.WaitGroup 35 | w.Add(1) 36 | t, err := strconv.Atoi(arguments[1]) 37 | if err != nil { 38 | fmt.Println(err) 39 | return 40 | } 41 | 42 | duration := time.Duration(int32(t)) * time.Millisecond 43 | fmt.Printf("Timeout period is %s\n", duration) 44 | 45 | if timeout(&w, duration) { 46 | fmt.Println("Timed out!") 47 | } else { 48 | fmt.Println("OK!") 49 | } 50 | w.Done() 51 | if timeout(&w, duration) { 52 | fmt.Println("Timed out!") 53 | } else { 54 | fmt.Println("OK!") 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /eBook/examples/chapter11/benchmarkMe.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func fibo1(n int) int { 8 | if n == 0 { 9 | return 0 10 | } else if n == 1 { 11 | return 1 12 | } else { 13 | return fibo1(n-1) + fibo1(n-2) 14 | } 15 | } 16 | 17 | func fibo2(n int) int { 18 | if n == 0 || n == 1 { 19 | return n 20 | } 21 | return fibo2(n-1) + fibo2(n-2) 22 | } 23 | 24 | func fibo3(n int) int { 25 | fn := make(map[int]int) 26 | for i := 0; i <= n; i++ { 27 | var f int 28 | if i <= 2 { 29 | f = 1 30 | } else { 31 | f = fn[i-1] + fn[i-2] 32 | } 33 | fn[i] = f 34 | } 35 | return fn[n] 36 | } 37 | 38 | func main() { 39 | fmt.Println(fibo1(40)) 40 | fmt.Println(fibo2(40)) 41 | fmt.Println(fibo3(40)) 42 | } 43 | -------------------------------------------------------------------------------- /eBook/examples/chapter11/benchmarkMe_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | var result int 8 | 9 | func benchmarkfibo1(b *testing.B, n int) { 10 | var r int 11 | for i := 0; i < b.N; i++ { 12 | r = fibo1(n) 13 | } 14 | result = r 15 | } 16 | 17 | func benchmarkfibo2(b *testing.B, n int) { 18 | var r int 19 | for i := 0; i < b.N; i++ { 20 | r = fibo2(n) 21 | } 22 | result = r 23 | } 24 | 25 | func benchmarkfibo3(b *testing.B, n int) { 26 | var r int 27 | for i := 0; i < b.N; i++ { 28 | r = fibo3(n) 29 | } 30 | result = r 31 | } 32 | 33 | func Benchmark30fibo1(b *testing.B) { 34 | benchmarkfibo1(b, 30) 35 | } 36 | 37 | func Benchmark30fibo2(b *testing.B) { 38 | benchmarkfibo2(b, 30) 39 | } 40 | 41 | func Benchmark30fibo3(b *testing.B) { 42 | benchmarkfibo3(b, 30) 43 | } 44 | 45 | func Benchmark50fibo1(b *testing.B) { 46 | benchmarkfibo1(b, 50) 47 | } 48 | 49 | func Benchmark50fibo2(b *testing.B) { 50 | benchmarkfibo2(b, 50) 51 | } 52 | 53 | func Benchmark50fibo3(b *testing.B) { 54 | benchmarkfibo3(b, 50) 55 | } 56 | -------------------------------------------------------------------------------- /eBook/examples/chapter11/betterProfile.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/pkg/profile" 7 | ) 8 | 9 | var VARIABLE int 10 | 11 | func N1(n int) bool { 12 | for i := 2; i < n; i++ { 13 | if (n % i) == 0 { 14 | return false 15 | } 16 | } 17 | return true 18 | } 19 | 20 | func Multiply(a, b int) int { 21 | if a == 1 { 22 | return b 23 | } 24 | if a == 0 || b == 0 { 25 | return 0 26 | } 27 | if a < 0 { 28 | return -Multiply(-a, b) 29 | } 30 | return b + Multiply(a-1, b) 31 | } 32 | func main() { 33 | defer profile.Start(profile.ProfilePath("/tmp")).Stop() 34 | total := 0 35 | for i := 2; i < 200000; i++ { 36 | n := N1(i) 37 | if n { 38 | total++ 39 | } 40 | fmt.Println("Total: ", total) 41 | } 42 | total = 0 43 | for i := 0; i < 5000; i++ { 44 | for j := 0; j < 400; j++ { 45 | k := Multiply(i, j) 46 | VARIABLE = k 47 | total++ 48 | } 49 | } 50 | fmt.Println("Total: ", total) 51 | } 52 | -------------------------------------------------------------------------------- /eBook/examples/chapter11/cannotReach.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func f1() int { 8 | fmt.Println("Entering f1()") 9 | return -10 10 | fmt.Println("Exiting f1()") 11 | return -1 12 | } 13 | 14 | func f2() int { 15 | if true { 16 | return 10 17 | } 18 | fmt.Println("Exiting f2()") 19 | return 0 20 | } 21 | 22 | func main() { 23 | fmt.Println(f1()) 24 | fmt.Println("Exiting program...") 25 | } 26 | -------------------------------------------------------------------------------- /eBook/examples/chapter11/documentMe.go: -------------------------------------------------------------------------------- 1 | // This package is for showcasing the documentation capabilities of Go 2 | // It is a naive package! 3 | package documentMe 4 | 5 | // Pie is a global variable 6 | // This is a silly comment! 7 | const Pie = 3.1415912 8 | 9 | // The S1() function finds the length of a string 10 | // It iterates over the string using range 11 | func S1(s string) int { 12 | if s == "" { 13 | return 0 14 | } 15 | n := 0 16 | for range s { 17 | n++ 18 | } 19 | return n 20 | } 21 | 22 | // The F1() function returns the double value of its input integer 23 | // A better function name would have been Double()! 24 | func F1(n int) int { 25 | return 2 * n 26 | } 27 | -------------------------------------------------------------------------------- /eBook/examples/chapter11/documentMe_test.go: -------------------------------------------------------------------------------- 1 | package documentMe 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func ExampleS1() { 8 | fmt.Println(S1("123456789")) 9 | fmt.Println(S1("")) 10 | // Output: 11 | // 9 12 | // 0 13 | } 14 | 15 | func ExampleF1() { 16 | fmt.Println(F1(10)) 17 | fmt.Println(F1(2)) 18 | // Output: 19 | // 1 20 | // 55 21 | } 22 | -------------------------------------------------------------------------------- /eBook/examples/chapter11/ex.go: -------------------------------------------------------------------------------- 1 | package ex 2 | 3 | func F1(n int) int { 4 | if n == 0 { 5 | return 0 6 | } 7 | if n == 1 || n == 2 { 8 | return 1 9 | } 10 | return F1(n-1) + F1(n-2) 11 | } 12 | 13 | func S1(s string) int { 14 | return len(s) 15 | } 16 | -------------------------------------------------------------------------------- /eBook/examples/chapter11/ex_test.go: -------------------------------------------------------------------------------- 1 | package ex 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func ExampleF1() { 8 | fmt.Println(F1(10)) 9 | fmt.Println(F1(2)) 10 | // Output: 11 | // 55 12 | // 1 13 | } 14 | 15 | func ExampleS1() { 16 | fmt.Println(S1("123456789")) 17 | fmt.Println(S1("")) 18 | // Output: 19 | // 8 20 | // 0 21 | } 22 | -------------------------------------------------------------------------------- /eBook/examples/chapter11/goGC.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "runtime" 7 | "runtime/trace" 8 | "time" 9 | ) 10 | 11 | func printStats(mem runtime.MemStats) { 12 | runtime.ReadMemStats(&mem) 13 | fmt.Println("mem.Alloc:", mem.Alloc) 14 | fmt.Println("mem.TotalAlloc:", mem.TotalAlloc) 15 | fmt.Println("mem.HeapAlloc:", mem.HeapAlloc) 16 | fmt.Println("-----") 17 | } 18 | 19 | func main() { 20 | f, err := os.Create("/tmp/traceFile.out") 21 | if err != nil { 22 | panic(err) 23 | } 24 | defer f.Close() 25 | err = trace.Start(f) 26 | if err != nil { 27 | fmt.Println(err) 28 | return 29 | } 30 | defer trace.Stop() 31 | 32 | var mem runtime.MemStats 33 | printStats(mem) 34 | for i := 0; i < 3; i++ { 35 | s := make([]byte, 50000000) 36 | if s == nil { 37 | fmt.Println("Operation failed!") 38 | } 39 | } 40 | printStats(mem) 41 | for i := 0; i < 5; i++ { 42 | s := make([]byte, 100000000) 43 | if s == nil { 44 | fmt.Println("Operation failed!") 45 | } 46 | time.Sleep(time.Millisecond) 47 | } 48 | printStats(mem) 49 | } 50 | -------------------------------------------------------------------------------- /eBook/examples/chapter11/testMe.go: -------------------------------------------------------------------------------- 1 | package testMe 2 | 3 | func f1(n int) int { 4 | if n == 0 { 5 | return 0 6 | } 7 | if n == 1 { 8 | return 1 9 | } 10 | return f1(n-1) + f1(n-2) 11 | } 12 | 13 | func f2(n int) int { 14 | if n == 0 { 15 | return 0 16 | } 17 | if n == 1 { 18 | return 2 19 | } 20 | return f2(n-1) + f2(n-2) 21 | } 22 | 23 | func s1(s string) int { 24 | if s == "" { 25 | return 0 26 | } 27 | n := 1 28 | for range s { 29 | n++ 30 | } 31 | return n 32 | } 33 | 34 | func s2(s string) int { 35 | return len(s) 36 | } 37 | -------------------------------------------------------------------------------- /eBook/examples/chapter11/testMe_test.go: -------------------------------------------------------------------------------- 1 | package testMe 2 | 3 | import "testing" 4 | 5 | func TestS1(t *testing.T) { 6 | if s1("123456789") != 9 { 7 | t.Error(`s1("123456789") != 9`) 8 | } 9 | if s1("") != 0 { 10 | t.Error(`s1("") != 0`) 11 | } 12 | } 13 | 14 | func TestS2(t *testing.T) { 15 | if s2("123456789") != 9 { 16 | t.Error(`s2("123456789") != 9`) 17 | } 18 | if s2("") != 0 { 19 | t.Error(`s2("") != 0`) 20 | } 21 | } 22 | 23 | func TestF1(t *testing.T) { 24 | if f1(0) != 0 { 25 | t.Error(`f1(0) != 0`) 26 | } 27 | if f1(1) != 1 { 28 | t.Error(`f1(1) != 1`) 29 | } 30 | if f1(2) != 1 { 31 | t.Error(`f1(2) != 1`) 32 | } 33 | if f1(10) != 55 { 34 | t.Error(`f1(10) != 55`) 35 | } 36 | } 37 | 38 | func TestF2(t *testing.T) { 39 | if f2(0) != 0 { 40 | t.Error(`f2(0) != 0`) 41 | } 42 | if f2(1) != 1 { 43 | t.Error(`f2(1) != 1`) 44 | } 45 | if f2(2) != 1 { 46 | t.Error(`f2(2) != 1`) 47 | } 48 | if f2(10) != 55 { 49 | t.Error(`f2(10) != 55`) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /eBook/examples/chapter11/writingBU_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "testing" 7 | ) 8 | 9 | var ERR error 10 | 11 | func benchmarkCreate(b *testing.B, buffer, filesize int) { 12 | var err error 13 | for i := 0; i < b.N; i++ { 14 | err = Create("/tmp/random", buffer, filesize) 15 | } 16 | ERR = err 17 | err = os.Remove("/tmp/random") 18 | if err != nil { 19 | fmt.Println(err) 20 | } 21 | } 22 | 23 | func Benchmark1Create(b *testing.B) { 24 | benchmarkCreate(b, 1, 1000000) 25 | } 26 | 27 | func Benchmark2Create(b *testing.B) { 28 | benchmarkCreate(b, 2, 1000000) 29 | } 30 | 31 | func Benchmark4Create(b *testing.B) { 32 | benchmarkCreate(b, 4, 1000000) 33 | } 34 | 35 | func Benchmark10Create(b *testing.B) { 36 | benchmarkCreate(b, 10, 1000000) 37 | } 38 | 39 | func Benchmark1000Create(b *testing.B) { 40 | benchmarkCreate(b, 1000, 1000000) 41 | } 42 | -------------------------------------------------------------------------------- /eBook/examples/chapter11/xCompile.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | func main() { 9 | fmt.Println("You are using ", runtime.Compiler, " ") 10 | fmt.Println("on a", runtime.GOARCH, "machine") 11 | fmt.Println("with Go version", runtime.Version()) 12 | } 13 | -------------------------------------------------------------------------------- /eBook/examples/chapter12/ NSrecords.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | arguments := os.Args 11 | if len(arguments) == 1 { 12 | fmt.Println("Need a domain name!") 13 | return 14 | } 15 | domain := arguments[1] 16 | NSs, err := net.LookupNS(domain) 17 | if err != nil { 18 | fmt.Println(err) 19 | return 20 | } 21 | 22 | for _, NS := range NSs { 23 | fmt.Println(NS.Host) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /eBook/examples/chapter12/DNS.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "os" 7 | ) 8 | 9 | func lookIP(address string) ([]string, error) { 10 | hosts, err := net.LookupAddr(address) 11 | if err != nil { 12 | return nil, err 13 | } 14 | return hosts, nil 15 | } 16 | 17 | func lookHostname(hostname string) ([]string, error) { 18 | IPs, err := net.LookupHost(hostname) 19 | if err != nil { 20 | return nil, err 21 | } 22 | return IPs, nil 23 | } 24 | 25 | func main() { 26 | arguments := os.Args 27 | if len(arguments) == 1 { 28 | fmt.Println("Please provide an argument!") 29 | return 30 | } 31 | 32 | input := arguments[1] 33 | IPaddress := net.ParseIP(input) 34 | if IPaddress == nil { 35 | IPs, err := lookHostname(input) 36 | if err == nil { 37 | for _, singleIP := range IPs { 38 | fmt.Println(singleIP) 39 | } 40 | } 41 | } else { 42 | hosts, err := lookIP(input) 43 | if err == nil { 44 | for _, hostname := range hosts { 45 | fmt.Println(hostname) 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /eBook/examples/chapter12/MXrecords.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | arguments := os.Args 11 | if len(arguments) == 1 { 12 | fmt.Println("Need a domain name!") 13 | return 14 | } 15 | domain := arguments[1] 16 | MXs, err := net.LookupMX(domain) 17 | if err != nil { 18 | fmt.Println(err) 19 | return 20 | } 21 | 22 | for _, MX := range MXs { 23 | fmt.Println(MX.Host) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /eBook/examples/chapter12/anotherTimeOut.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net/http" 7 | "os" 8 | "strconv" 9 | "time" 10 | ) 11 | 12 | var timeout = time.Duration(time.Second) 13 | 14 | func main() { 15 | if len(os.Args) == 1 { 16 | fmt.Println("Please provide a URL") 17 | return 18 | } 19 | 20 | if len(os.Args) == 3 { 21 | temp, err := strconv.Atoi(os.Args[2]) 22 | if err != nil { 23 | fmt.Println("Using Default Timeout!") 24 | } else { 25 | timeout = time.Duration(time.Duration(temp) * time.Second) 26 | } 27 | } 28 | 29 | URL := os.Args[1] 30 | 31 | client := http.Client{ 32 | Timeout: timeout, 33 | } 34 | client.Get(URL) 35 | 36 | data, err := client.Get(URL) 37 | if err != nil { 38 | fmt.Println(err) 39 | return 40 | } else { 41 | defer data.Body.Close() 42 | _, err := io.Copy(os.Stdout, data.Body) 43 | if err != nil { 44 | fmt.Println(err) 45 | return 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /eBook/examples/chapter12/clientTimeOut.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net" 7 | "net/http" 8 | "os" 9 | "path/filepath" 10 | "strconv" 11 | "time" 12 | ) 13 | 14 | var timeout = time.Duration(time.Second) 15 | 16 | func Timeout(network, host string) (net.Conn, error) { 17 | conn, err := net.DialTimeout(network, host, timeout) 18 | if err != nil { 19 | return nil, err 20 | } 21 | conn.SetDeadline(time.Now().Add(timeout)) 22 | return conn, nil 23 | } 24 | 25 | func main() { 26 | if len(os.Args) == 1 { 27 | fmt.Printf("Usage: %s URL TIMEOUT\n", filepath.Base(os.Args[0])) 28 | return 29 | } 30 | 31 | if len(os.Args) == 3 { 32 | temp, err := strconv.Atoi(os.Args[2]) 33 | if err != nil { 34 | fmt.Println("Using Default Timeout!") 35 | } else { 36 | timeout = time.Duration(time.Duration(temp) * time.Second) 37 | } 38 | } 39 | 40 | URL := os.Args[1] 41 | t := http.Transport{ 42 | Dial: Timeout, 43 | } 44 | 45 | client := http.Client{ 46 | Transport: &t, 47 | } 48 | 49 | data, err := client.Get(URL) 50 | if err != nil { 51 | fmt.Println(err) 52 | return 53 | } else { 54 | defer data.Body.Close() 55 | _, err := io.Copy(os.Stdout, data.Body) 56 | if err != nil { 57 | fmt.Println(err) 58 | return 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /eBook/examples/chapter12/home.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | A Key Value Store! 6 | 7 | 8 | 9 | Home sweet home! 10 | List all elements! 11 | Change an elements! 12 | Insert an elements! 13 | 14 |

Welcome to the Go KV store!

15 | 16 | -------------------------------------------------------------------------------- /eBook/examples/chapter12/httpTrace.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net/http" 7 | "net/http/httptrace" 8 | "os" 9 | ) 10 | 11 | func main() { 12 | if len(os.Args) != 2 { 13 | fmt.Println("Usage: URL\n") 14 | return 15 | } 16 | URL := os.Args[1] 17 | client := http.Client{} 18 | 19 | req, _ := http.NewRequest("GET", URL, nil) 20 | trace := &httptrace.ClientTrace{ 21 | GotFirstResponseByte: func() { 22 | fmt.Println("First response byte!") 23 | }, 24 | GotConn: func(connInfo httptrace.GotConnInfo) { 25 | fmt.Printf("Got Conn: %+v\n", connInfo) 26 | }, 27 | DNSDone: func(dnsInfo httptrace.DNSDoneInfo) { 28 | fmt.Printf("DNS Info: %+v\n", dnsInfo) 29 | }, 30 | ConnectStart: func(network, addr string) { 31 | fmt.Println("Dial start") 32 | }, 33 | ConnectDone: func(network, addr string, err error) { 34 | fmt.Println("Dial done") 35 | }, 36 | WroteHeaders: func() { 37 | fmt.Println("Wrote headers") 38 | }, 39 | } 40 | 41 | req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace)) 42 | fmt.Println("Requesting data from server!") 43 | _, err := http.DefaultTransport.RoundTrip(req) 44 | if err != nil { 45 | fmt.Println(err) 46 | return 47 | } 48 | 49 | response, err := client.Do(req) 50 | if err != nil { 51 | fmt.Println(err) 52 | return 53 | } 54 | io.Copy(os.Stdout, response.Body) 55 | } 56 | -------------------------------------------------------------------------------- /eBook/examples/chapter12/insert.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | A Key Value Store! 6 | 7 | 8 | 9 | Home sweet home! 10 | List all elements! 11 | Change an elements! 12 | Insert an elements! 13 | 14 | {{if .Success}} 15 |

Element inserted!

16 | {{else}} 17 |

Please fill in the fields:

18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | 28 |
29 | {{end}} 30 | 31 | 32 | -------------------------------------------------------------------------------- /eBook/examples/chapter12/netCapabilities.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | ) 7 | 8 | func main() { 9 | interfaces, err := net.Interfaces() 10 | if err != nil { 11 | fmt.Print(err) 12 | return 13 | } 14 | 15 | for _, i := range interfaces { 16 | fmt.Printf("Name: %v\n", i.Name) 17 | fmt.Println("Interface Flags:", i.Flags.String()) 18 | fmt.Println("Interface MTU:", i.MTU) 19 | fmt.Println("Interface Hardware Address:", i.HardwareAddr) 20 | fmt.Println() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /eBook/examples/chapter12/netConfig.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | ) 7 | 8 | func main() { 9 | interfaces, err := net.Interfaces() 10 | if err != nil { 11 | fmt.Println(err) 12 | return 13 | } 14 | for _, i := range interfaces { 15 | fmt.Printf("Interface: %v\n", i.Name) 16 | byName, err := net.InterfaceByName(i.Name) 17 | if err != nil { 18 | fmt.Println(err) 19 | } 20 | addresses, err := byName.Addrs() 21 | for k, v := range addresses { 22 | fmt.Printf("Interface Address #%v: %v\n", k, v.String()) 23 | } 24 | fmt.Println() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /eBook/examples/chapter12/serverTimeOut.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "os" 7 | "time" 8 | ) 9 | 10 | func myHandler(w http.ResponseWriter, r *http.Request) { 11 | fmt.Fprintf(w, "Serving: %s\n", r.URL.Path) 12 | fmt.Fprintf("Served: %s\n", r.Host) 13 | } 14 | 15 | func timeHandler(w http.ResponseWriter, r *http.Request) { 16 | t := time.Now().Format(time.RFC1123) 17 | Body := "The current time is:" 18 | fmt.Fprintf(w, "

%s

", Body) 19 | fmt.Fprintf(w, "

%s

n", t) 20 | fmt.Fprintf(w, "Serving: %s\n", r.URL.Path) 21 | fmt.Printf("Served time for :%s\n", r.Host) 22 | } 23 | 24 | func main() { 25 | PORT := ":8001" 26 | arguments := os.Args 27 | if len(arguments) == 1 { 28 | fmt.Printf("Listening on http://0.0.0.0%s\n", PORT) 29 | } else { 30 | PORT = ":" + arguments[1] 31 | fmt.Printf("Listening on http://0.0.0.0%s\n", PORT) 32 | } 33 | 34 | m := http.NewServeMux() 35 | srv := &http.Server{ 36 | Addr: PORT, 37 | Handler: m, 38 | ReadTimeout: 3 * time.Second, 39 | WriteTimeout: 3 * time.Second, 40 | } 41 | 42 | m.HandleFunc("/time".timeHandler) 43 | m.HandleFunc("/", myHandler) 44 | 45 | err := srv.ListenAndServe() 46 | if err != nil { 47 | fmt.Println(err) 48 | return 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /eBook/examples/chapter12/testWWW.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "os" 7 | ) 8 | 9 | func CheckStatusOK(w http.ResponseWriter, r *http.Request) { 10 | w.WriteHeader(http.StatusOK) 11 | fmt.Fprintf(w, `Fine!`) 12 | } 13 | 14 | func StatusNotFound(w http.ResponseWriter, r *http.Request) { 15 | fmt.Fprintf(w, "Serving: %s\n", r.URL.Path) 16 | fmt.Printf("Served: %s\n", r.Host) 17 | } 18 | 19 | func MyHandler(w http.ResponseWriter, r *http.Request) { 20 | fmt.Fprintf(w, "Serving: %s\n", r.URL.Path) 21 | fmt.Printf("Served: %s\n", r.Host) 22 | } 23 | 24 | func main() { 25 | PORT := ":8001" 26 | arguments := os.Args 27 | if len(arguments) == 1 { 28 | fmt.Println("Using default port number:", PORT) 29 | } else { 30 | PORT = ":" + arguments[1] 31 | } 32 | 33 | http.HandleFunc("/CheckStatusOK", CheckStatusOK) 34 | http.HandleFunc("/StatusNotFound", StatusNotFound) 35 | http.HandleFunc("/", MyHandler) 36 | 37 | err := http.ListenAndServe(PORT, nil) 38 | if err != nil { 39 | fmt.Println(err) 40 | return 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /eBook/examples/chapter12/testWWW_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "net/http/httptest" 7 | "testing" 8 | ) 9 | 10 | func TestCheckStatusOK(t *testing.T) { 11 | req, err := http.NewRequest("GET", "/CheckStatusOK", nil) 12 | if err != nil { 13 | fmt.Println(err) 14 | return 15 | } 16 | 17 | rr := httptest.NewRecorder() 18 | handler := http.HandlerFunc(CheckStatusOK) 19 | handler.ServeHTTP(rr, req) 20 | 21 | status := rr.Code 22 | if status != http.StatusOK { 23 | t.Errorf("handler returned %v", status) 24 | } 25 | 26 | expect := `Fine!` 27 | if rr.Body.String() != expect { 28 | t.Errorf("handler returned %v", rr.Body.String()) 29 | } 30 | } 31 | 32 | func TestStatusNotFound(t *testing.T) { 33 | req, err := http.NewRequest("GET", "/StatusNotFound", nil) 34 | if err != nil { 35 | fmt.Println(err) 36 | return 37 | } 38 | 39 | rr := httptest.NewRecorder() 40 | handler := http.HandlerFunc(StatusNotFound) 41 | handler.ServeHTTP(rr, req) 42 | 43 | status := rr.Code 44 | if status != http.StatusNotFound { 45 | t.Errorf("handler returned %v", status) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /eBook/examples/chapter12/update.gohtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | A Key Value Store! 6 | 7 | 8 | 9 | Home sweet home! 10 | List all elements! 11 | Change an elements! 12 | Insert an elements! 13 | 14 | {{if .Success}}

Element updated!

{{else}} 15 |

Please fill in the fields:

16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | 26 |
27 | {{end}} 28 | 29 | 30 | -------------------------------------------------------------------------------- /eBook/examples/chapter12/webClient.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net/http" 7 | "os" 8 | "path/filepath" 9 | ) 10 | 11 | func main() { 12 | if len(os.Args) != 2 { 13 | fmt.Printf("Usage: %s URL\n", filepath.Base(os.Args[0])) 14 | return 15 | } 16 | 17 | URL := os.Args[1] 18 | 19 | data, err := http.Get(URL) 20 | 21 | if err != nil { 22 | fmt.Println(err) 23 | return 24 | } else { 25 | defer data.Body.Close() 26 | _, err := io.Copy(os.Stdout, data.Body) 27 | if err != nil { 28 | fmt.Println(err) 29 | return 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /eBook/examples/chapter12/www.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "os" 7 | "time" 8 | ) 9 | 10 | func myHandler(w http.ResponseWriter, r *http.Request) { 11 | fmt.Fprintf(w, "Serving: %s\n", r.URL.Path) 12 | fmt.Printf("Served: %s\n", r.Host) 13 | } 14 | 15 | func timeHandler(w http.ResponseWriter, r *http.Request) { 16 | t := time.Now().Format(time.RFC1123) 17 | Body := "The current time is:" 18 | fmt.Fprintf(w, "

%s

", Body) 19 | fmt.Fprintf(w, "

%s

\n", t) 20 | fmt.Fprintf(w, "Serving: %s\n", r.URL.Path) 21 | fmt.Printf("Served time for: %s\n", r.Host) 22 | } 23 | 24 | func main() { 25 | PORT := ":8001" 26 | arguments := os.Args 27 | if len(arguments) == 1 { 28 | fmt.Println("Using default port number: ", PORT) 29 | } else { 30 | PORT = ":" + arguments[1] 31 | } 32 | http.HandleFunc("/time", timeHandler) 33 | http.HandleFunc("/", myHandler) 34 | 35 | err := http.ListenAndServe(PORT, nil) 36 | if err != nil { 37 | fmt.Println(err) 38 | return 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /eBook/examples/chapter12/wwwProfile.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "net/http/pprof" 7 | "os" 8 | "time" 9 | ) 10 | 11 | func myHandler(w http.ResponseWriter, r *http.Request) { 12 | fmt.Fprintf(w, "Serving: %s\n", r.URL.Path) 13 | fmt.Printf("Served: %s\n", r.Host) 14 | } 15 | 16 | func timeHandler(w http.ResponseWriter, r *http.Request) { 17 | t := time.Now().Format(time.RFC1123) 18 | Body := "The current time is:" 19 | fmt.Fprintf(w, "

%s

", Body) 20 | fmt.Fprintf(w, "

%s

\n", t) 21 | fmt.Fprintf(w, "Serving: %s\n", r.URL.Path) 22 | fmt.Printf("Served time for: %s\n", r.Host) 23 | } 24 | 25 | func main() { 26 | PORT := ":8001" 27 | arguments := os.Args 28 | if len(arguments) == 1 { 29 | fmt.Println("Using default port number: ", PORT) 30 | } else { 31 | PORT = ":" + arguments[1] 32 | fmt.Println("Using port number: ", PORT) 33 | } 34 | 35 | r := http.NewServeMux() 36 | r.HandleFunc("/time", timeHandler) 37 | r.HandleFunc("/", myHandler) 38 | r.HandleFunc("/debug/pprof/", pprof.Index) 39 | r.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) 40 | r.HandleFunc("/debug/pprof/profile", pprof.Profile) 41 | r.HandleFunc("/debug/pprof/symbol", pprof.Symbol) 42 | r.HandleFunc("/debug/pprof/trace", pprof.Trace) 43 | err := http.ListenAndServe(PORT, r) 44 | if err != nil { 45 | fmt.Println(err) 46 | return 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /eBook/examples/chapter13/RPCclient.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/rpc" 6 | "os" 7 | "sharedRPC" 8 | ) 9 | 10 | func main() { 11 | arguments := os.Args 12 | if len(arguments) == 1 { 13 | fmt.Println("Please provide a host:port sting!") 14 | return 15 | } 16 | 17 | CONNECT := arguments[1] 18 | c, err := rpc.Dial("tcp", CONNECT) 19 | if err != nil { 20 | fmt.Println(err) 21 | return 22 | } 23 | args := sharedRPC.MyFloats(16, -0.5) 24 | var reply float64 25 | 26 | err = c.Call("MyInterface.Multiply", args, &reply) 27 | if err != nil { 28 | fmt.Println(err) 29 | return 30 | } 31 | fmt.Printf("Reply (Multiply): %f\n", reply) 32 | 33 | err = c.Call("MyInterface.Power", argus, &reply) 34 | if err != nil { 35 | fmt.Println(err) 36 | return 37 | } 38 | fmt.Printf("Reply (Power): %f\n", reply) 39 | } 40 | -------------------------------------------------------------------------------- /eBook/examples/chapter13/RPCserver.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "net" 7 | "net/rpc" 8 | "os" 9 | "sharedRPC" 10 | ) 11 | 12 | type MyInterface struct{} 13 | 14 | func Power(x, y float64) float64 { 15 | return math.Pow(x, y) 16 | } 17 | 18 | func (t *MyInterface) Multiply(arguments *sharedRPC.MyFloats, reply *float64) error { 19 | *reply = arguments.A1 * argumentsA2 20 | return nil 21 | } 22 | 23 | func (t *MyInterface) Power(arguments *sharedRPC.MyFloats, reply *float64) error { 24 | *reply = Power(arguments.A1, arguments.A2) 25 | return nil 26 | } 27 | 28 | func main() { 29 | PORT := ":1234" 30 | arguments := os.Args 31 | if len(arguments) != 1 { 32 | PORT = ":" + arguments[1] 33 | } 34 | 35 | myInterface := new(MyInterface) 36 | rpc.Register(myInterface) 37 | t, err := net.ResolveTCPAddr("tcp4", PORT) 38 | if err != nil { 39 | fmt.Println(err) 40 | return 41 | } 42 | l, err := net.ListenTCP("tcp4", t) 43 | if err != nil { 44 | fmt.Println(err) 45 | return 46 | } 47 | for { 48 | c, err := l.Accept() 49 | if err != nil { 50 | continue 51 | } 52 | fmt.Printf("%s\n", c.RemoteAddr()) 53 | rpc.ServerConn(c) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /eBook/examples/chapter13/TCPclient.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "net" 7 | "os" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | arguments := os.Args 13 | if len(arguments) == 1 { 14 | fmt.Println("Please provide host:port.") 15 | return 16 | } 17 | CONNECT := arguments[1] 18 | c, err := net.Dial("tcp", CONNECT) 19 | if err != nil { 20 | fmt.Println(err) 21 | return 22 | } 23 | 24 | for { 25 | reader := bufio.NewReader(os.Stdin) 26 | fmt.Print(">> ") 27 | text, _ := reader.ReadString('\n') 28 | fmt.Fprintf(c, text+"\n") 29 | 30 | message, _ := bufio.NewReader(c).ReadString('\n') 31 | fmt.Print("->: " + message) 32 | if strings.TrimSpace(string(text)) == "STOP" { 33 | fmt.Println("TCP client exiting...") 34 | return 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /eBook/examples/chapter13/TCPserver.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "net" 7 | "os" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | func main() { 13 | arguments := os.Args 14 | if len(arguments) == 1 { 15 | fmt.Println("Please provide port number") 16 | return 17 | } 18 | 19 | PORT := ":" + arguments[1] 20 | l, err := net.Listen("tcp", PORT) 21 | if err != nil { 22 | fmt.Println(err) 23 | return 24 | } 25 | defer l.Close() 26 | 27 | c, err := l.Accept() 28 | if err != nil { 29 | fmt.Println(err) 30 | return 31 | } 32 | 33 | for { 34 | netData, err := bufio.NewReader(c).ReadString('\n') 35 | if err != nil { 36 | fmt.Println(err) 37 | return 38 | } 39 | if strings.TrimSpace(string(netData)) == "STOP" { 40 | fmt.Println("Exiting TCP server!") 41 | return 42 | } 43 | fmt.Print("-> ", string(netData)) 44 | t := time.Now() 45 | myTime := t.Format(time.RFC3339) + "\n" 46 | c.Write([]byte(myTime)) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /eBook/examples/chapter13/UDPserver.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import( 4 | "fmt" 5 | "math/rand" 6 | "net" 7 | "os" 8 | "strconv" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | func random(min, max, int) int { 14 | return rand.Intn(max-min) + min 15 | } 16 | 17 | func main() { 18 | arguments := os.Args 19 | if len(arguments) == 1 { 20 | fmt.Println("Please provide a port number!") 21 | return 22 | } 23 | PORT := ":" + arguments[1] 24 | 25 | s, err := net.ResolveUDPAddr("udp4", PORT) 26 | if err != nil { 27 | fmt.Println(err) 28 | return 29 | } 30 | 31 | connection, err := net.ListenUDP("udp4", s) 32 | if err != nil { 33 | fmt.Println(err) 34 | return 35 | } 36 | 37 | defer connection.Close() 38 | buffer := make([]byte, 1024) 39 | rand.Seed(time.Now().Unix()) 40 | 41 | for { 42 | n, addr, err := connection.ReadFromUDP(buffer) 43 | fmt.Print("->", string(buffer[0:n-1])) 44 | 45 | if strings.TrimSpace(string(buffer[0:n])) == "STOP" { 46 | fmt.Println("Exiting UDP server!") 47 | return 48 | } 49 | 50 | data := []byte(strconv.Itoa(random[1, 1001])) 51 | fmt.Printf("data: %s\n", string(data)) 52 | _, err = connection.WriteToUDP(data, addr) 53 | if err != nil { 54 | fmt.Println(err) 55 | return 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /eBook/examples/chapter13/fiboTCP.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "net" 7 | "os" 8 | "strconv" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | func f(n int) int { 14 | fn := make(map[int]int) 15 | for i := 0; i <= n; i++ { 16 | var f int 17 | if i <= 2 { 18 | f = 1 19 | } else { 20 | f = fn[i-1] + fn[i-2] 21 | } 22 | fn[i] = f 23 | } 24 | return fn[n] 25 | } 26 | 27 | func handleConnection(c net.Conn) { 28 | for { 29 | netData, err := bufio.NewReader(c).ReadString('\n') 30 | if err != nil { 31 | fmt.Println(err) 32 | os.Exit(100) 33 | } 34 | 35 | temp := strings.TrimSpace(string(netData)) 36 | if temp == "STOP" { 37 | break 38 | } 39 | 40 | fibo := "-1\n" 41 | n, err := strconv.Atoi(temp) 42 | if err == nil { 43 | fibo = strconv.Itoa(f(n)) + "\n" 44 | } 45 | c.Write([]byte(string(fibo))) 46 | } 47 | time.Sleep(5 * time.Second) 48 | c.Close() 49 | } 50 | 51 | func main() { 52 | arguments := os.Args 53 | if len(arguments) == 1 { 54 | fmt.Println("Please provide a port number!") 55 | return 56 | } 57 | 58 | PORT := ":" + arguments[1] 59 | l, err := net.Listen("tcp4", PORT) 60 | if err != nil { 61 | fmt.Println(err) 62 | return 63 | } 64 | defer l.Close() 65 | 66 | for { 67 | c, err := l.Accept() 68 | if err != nil { 69 | fmt.Println(err) 70 | return 71 | } 72 | go handleConnection(c) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /eBook/examples/chapter13/lowLevel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | ) 7 | 8 | func main() { 9 | netaddr, err := net.ResolveIPAddr("ip4", "127.0.0.1") 10 | if err != nil { 11 | fmt.Println(err) 12 | return 13 | } 14 | 15 | conn, err := net.ListenIP("ip4:icmp", netaddr) 16 | if err != nil { 17 | fmt.Println(err) 18 | return 19 | } 20 | 21 | buffer := make([]byte, 1024) 22 | n, _, err := conn.ReadFrom(buffer) 23 | if err != nil { 24 | fmt.Println(err) 25 | return 26 | } 27 | fmt.Printf("% X\n", buffer[0:n]) 28 | } 29 | -------------------------------------------------------------------------------- /eBook/examples/chapter13/otherTCPclient.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "net" 7 | "os" 8 | "strings" 9 | ) 10 | 11 | func main() { 12 | 13 | arguments := os.Args 14 | if len(arguments) == 1 { 15 | fmt.Println("Please provide a server:port string!") 16 | return 17 | } 18 | 19 | CONNECT := arguments[1] 20 | tcpAddr, err := net.ResolveTCPAddr("tcp4", CONNECT) 21 | if err != nil { 22 | fmt.Println("ResolveTCPAddr:", err.Error()) 23 | return 24 | } 25 | 26 | conn, err := net.DialTCP("tcp4", nil, tcpAddr) 27 | if err != nil { 28 | fmt.Println("DialTCP:", err.Error()) 29 | return 30 | } 31 | 32 | for { 33 | reader := bufio.NewReader(os.Stdin) 34 | fmt.Print(">> ") 35 | text, _ := reader.ReadString('\n') 36 | fmt.Fprintf(conn, text+"\n") 37 | 38 | message, _ := bufio.NewReader(conn).ReadString('\n') 39 | fmt.Print("->: " + message) 40 | if strings.TrimSpace(string(text)) == "STOP" { 41 | fmt.Println("TCP client exiting...") 42 | conn.Close() 43 | return 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /eBook/examples/chapter13/sharedRPC.go: -------------------------------------------------------------------------------- 1 | package sharedRPC 2 | 3 | type MyFloats struct { 4 | A1, A2 float64 5 | } 6 | 7 | type MyInterface interface { 8 | Multiply(arguments *MyFloats, reply *float64) error 9 | Power(arguments *MyFloats, reply *float64) error 10 | } 11 | -------------------------------------------------------------------------------- /eBook/examples/chapter13/syscallNet.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "syscall" 7 | ) 8 | 9 | func main() { 10 | fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_ICMP) 11 | if err != nil { 12 | fmt.Println("Error in syscall.Socket:", err) 13 | return 14 | } 15 | f := os.NewFile(uintptr(fd), "captureICMP") 16 | if f == nil { 17 | fmt.Println("Error is os.NewFile:", err) 18 | return 19 | } 20 | err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, 256) 21 | if err != nil { 22 | fmt.Println("Error in syscall.Socket:", err) 23 | return 24 | } 25 | for { 26 | buf := make([]byte, 1024) 27 | numRead, err := f.Read(buf) 28 | if err != nil { 29 | fmt.Println(err) 30 | } 31 | fmt.Printf("% X\n", buf[:numRead]) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /eBook/examples/chapter3/constants.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Digit int 6 | type Power2 int 7 | 8 | const PI = 3.1415926 9 | 10 | const ( 11 | 12 | C1 = "C1C1C1" 13 | 14 | C2 = "C2C2C2" 15 | 16 | C3 = "C3C3C3" 17 | 18 | ) 19 | 20 | func main() { 21 | 22 | const s1 = 123 23 | var v1 float32 = s1 * 12 24 | fmt.Println(v1) 25 | fmt.Println(PI) 26 | 27 | const ( 28 | Zero Digit = iota 29 | One 30 | Two 31 | Three 32 | Four 33 | ) 34 | fmt.Println(One) 35 | fmt.Println(Two) 36 | 37 | const ( 38 | p2_0 Power2 = 1 << iota 39 | _ 40 | p2_2 41 | _ 42 | p2_4 43 | _ 44 | p2_6 45 | ) 46 | 47 | fmt.Println("2^0:", p2_0) 48 | fmt.Println("2^2:", p2_2) 49 | fmt.Println("2^4:", p2_4) 50 | fmt.Println("2^6:", p2_6) 51 | 52 | 53 | } -------------------------------------------------------------------------------- /eBook/examples/chapter3/copySlice.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | a6 := []int{-10, 1, 2, 3, 4, 5} 7 | a4 := []int{-1, -2, -3, -4} 8 | fmt.Println("a6:", a6) 9 | fmt.Printf("a4:", a4) 10 | 11 | copy(a6, a4) 12 | fmt.Println("a6:", a6) 13 | fmt.Printf("a4:", a4) 14 | fmt.Println() 15 | 16 | b6 := []int{-10, 1, 2, 3, 4, 5} 17 | b4 := []int{-1, -2, -3, -4} 18 | fmt.Println("b6:", b6) 19 | fmt.Printf("b4:", b4) 20 | 21 | copy(b4, b6) 22 | fmt.Println("b6:", b6) 23 | fmt.Printf("b4:", b4) 24 | fmt.Println() 25 | 26 | fmt.Println() 27 | array4 := [4]int{4, -4, 4, -4} 28 | s6 := []int{1, -1, 1, -1, -5, 5} 29 | 30 | copy(s6, array4[0:]) 31 | fmt.Println("array4:", array4[0:]) 32 | fmt.Printf("s6:", s6) 33 | fmt.Println() 34 | 35 | array5 := [5]int{5, -5, 5, -5, 5} 36 | s7 := []int{7, 7, -7, 7, -7, 7} 37 | copy(array5[0:], s7) 38 | fmt.Println("array5:", array5) 39 | fmt.Printf("s7:", s7) 40 | fmt.Println() 41 | 42 | } 43 | -------------------------------------------------------------------------------- /eBook/examples/chapter3/failMap.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | //aMap := map[string]int{} 7 | // 8 | //aMap["test"] = 1 9 | //aMap := make(string)int{} 10 | // 11 | //aMap = nil 12 | // 13 | //fmt.Println(aMap) 14 | 15 | aMap["test"] = 1 16 | } 17 | -------------------------------------------------------------------------------- /eBook/examples/chapter3/lenCap.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func printSlice(x []int) { 6 | for _, number := range x { 7 | fmt.Println(number, " ") 8 | } 9 | fmt.Println() 10 | } 11 | 12 | func main() { 13 | aSlice := []int{-1, 0, 4} 14 | fmt.Printf("aSlice: ") 15 | printSlice(aSlice) 16 | 17 | fmt.Printf("Cap: %d, Length: %d\n", cap(aSlice), len(aSlice)) 18 | aSlice = append(aSlice, -100) 19 | fmt.Printf("aSlice: ") 20 | printSlice(aSlice) 21 | fmt.Printf("Cap: %d, Length: %d\n", cap(aSlice), len(aSlice)) 22 | 23 | aSlice = append(aSlice, -2) 24 | aSlice = append(aSlice, -3) 25 | aSlice = append(aSlice, -4) 26 | printSlice(aSlice) 27 | fmt.Printf("Cap: %d, Length: %d\n", cap(aSlice), len(aSlice)) 28 | } 29 | -------------------------------------------------------------------------------- /eBook/examples/chapter3/parseDate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | var myDate string 12 | 13 | if len(os.Args) != 2 { 14 | fmt.Printf("Usage: %s date\n", 15 | filepath.Base(os.Args[0])) 16 | os.Exit(0) 17 | } 18 | 19 | myDate = os.Args[1] 20 | d,err := time.Parse("02 January 2006",myDate) 21 | if err == nil { 22 | fmt.Println("Full",d) 23 | fmt.Println("Time", d.Day(), d.Month(), d.Year()) 24 | } else { 25 | fmt.Println(err) 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /eBook/examples/chapter3/parseTime.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | var myTime string 12 | 13 | if len(os.Args) != 2 { 14 | fmt.Printf("Usage: %s string\n", 15 | filepath.Base(os.Args[0])) 16 | os.Exit(0) 17 | } 18 | 19 | myTime = os.Args[1] 20 | d,err := time.Parse("15:04",myTime) 21 | if err == nil { 22 | fmt.Println("Full",d) 23 | fmt.Println("Time", d.Hour(), d.Minute()) 24 | } else { 25 | fmt.Println(err) 26 | } 27 | } -------------------------------------------------------------------------------- /eBook/examples/chapter3/pointers.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func getPointer(n *int) { 6 | *n = *n * *n 7 | } 8 | 9 | func returnPointer(n int) *int { 10 | v := n * n 11 | return &v 12 | } 13 | 14 | func main() { 15 | i := -10 16 | j := 25 17 | 18 | pI := &i 19 | pJ := &j 20 | 21 | fmt.Println("pI memory:", pI) 22 | fmt.Println("pJ memory:", pJ) 23 | fmt.Println("pI value:", *pI) 24 | fmt.Println("pJ memory:", *pJ) 25 | 26 | *pI = 123456 27 | *pI-- 28 | fmt.Println("i:", i) 29 | 30 | getPointer(pJ) 31 | fmt.Println("j:", j) 32 | k := returnPointer(12) 33 | fmt.Println(*k) 34 | fmt.Println(k) 35 | 36 | } 37 | -------------------------------------------------------------------------------- /eBook/examples/chapter3/slices.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | aSlice := []int{1, 2, 3, 4, 5} 7 | fmt.Println(aSlice) 8 | integer := make([]int, 2) 9 | fmt.Println(integer) 10 | integer = nil 11 | fmt.Println(integer) 12 | 13 | anArray := [5]int{-1, -2, -3, -4, -5} 14 | refAnArray := anArray[:] 15 | 16 | fmt.Println(anArray) 17 | fmt.Println(refAnArray) 18 | anArray[4] = -100 19 | fmt.Println(refAnArray) 20 | 21 | s := make([]byte, 5) 22 | fmt.Println(s) 23 | twoD := make([][]int, 3) 24 | fmt.Println(twoD) 25 | fmt.Println() 26 | 27 | for i := 0; i < len(twoD); i++ { 28 | for j := 0; j < 2; j++ { 29 | twoD[i] = append(twoD[i], i*j) 30 | } 31 | } 32 | 33 | for _, x := range twoD { 34 | for i, y := range x { 35 | fmt.Println("i:", i, "value:", y) 36 | } 37 | 38 | fmt.Println() 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /eBook/examples/chapter3/sortSlice.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sort" 6 | ) 7 | 8 | type aStructure struct { 9 | person string 10 | height int 11 | weight int 12 | } 13 | 14 | func main() { 15 | mySlice := make([]aStructure, 0) 16 | mySlice = append(mySlice, aStructure{"Mihalis", 180, 90}) 17 | mySlice = append(mySlice, aStructure{"Bill", 134, 45}) 18 | mySlice = append(mySlice, aStructure{"Merietta", 155, 45}) 19 | mySlice = append(mySlice, aStructure{"Epifanios", 144, 50}) 20 | mySlice = append(mySlice, aStructure{"Athina", 134, 40}) 21 | 22 | fmt.Println("0:", mySlice) 23 | 24 | sort.Slice(mySlice, func(i, j int) bool { 25 | return mySlice[i].height < mySlice[j].height 26 | }) 27 | fmt.Println("<:", mySlice) 28 | 29 | sort.Slice(mySlice, func(i, j int) bool { 30 | return mySlice[i].height > mySlice[j].height 31 | }) 32 | fmt.Println(">:", mySlice) 33 | } 34 | -------------------------------------------------------------------------------- /eBook/examples/chapter3/timeDate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | 11 | logs := []string{"127.0.0.1 - - [16/Nov/2017:10:49:46 +0200] 325504", 12 | "127.0.0.1 - - [16/Nov/2017:10:16:41 +0200] \"GET /CVEN HTTP/1.1\" 200 12531 \"-\" \"Mozilla/5.0 AppleWebKit/537.36", 13 | "127.0.0.1 200 9412 - - [12/Nov/2017:06:26:05 +0200] \"GET \"http://www.mtsoukalos.eu/taxonomy/term/47\" 1507", 14 | "[12/Nov/2017:16:27:21 +0300]", 15 | "[12/Nov/2017:20:88:21 +0200]", 16 | "[12/Nov/2017:20:21 +0200]", 17 | } 18 | 19 | for _, logEntry := range logs { 20 | r := regexp.MustCompile(`.*\[(\d\d\/\w+/\d\d\d\d:\d\d:\d\d:\d\d.*)\].*`) 21 | if r.MatchString(logEntry) { 22 | match := r.FindStringSubmatch(logEntry) 23 | dt, err := time.Parse("02/Jan/2006:15:04:05 -0700", match[1]) 24 | if err == nil { 25 | newFormat := dt.Format(time.RFC850) 26 | fmt.Println(newFormat) 27 | } else { 28 | fmt.Println("Not a valid date time format!") 29 | } 30 | } else { 31 | fmt.Println("Not a match!") 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /eBook/examples/chapter3/usingMaps.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | iMap := make(map[string]int) 9 | iMap["k1"] = 12 10 | iMap["k2"] = 13 11 | fmt.Println("iMap:", iMap) 12 | 13 | anotherMap := map[string]int{ 14 | "k1": 12, 15 | "k2": 13, 16 | } 17 | fmt.Println("anotherMap:", anotherMap) 18 | delete(anotherMap, "k1") 19 | delete(anotherMap, "k1") 20 | delete(anotherMap, "k1") 21 | fmt.Println("anotherMap:", anotherMap) 22 | 23 | _, ok := iMap["doseItExist"] 24 | if ok { 25 | fmt.Println("Exist!") 26 | } else { 27 | fmt.Println("dose NOT exist") 28 | } 29 | 30 | for key, value := range iMap { 31 | fmt.Println(key, value) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /eBook/examples/chapter3/usingTime.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | fmt.Println("Epoch Time:", time.Now().Unix()) 10 | t := time.Now() 11 | fmt.Println(t, t.Format(time.RFC3339)) 12 | fmt.Println(t.Weekday(), t.Day(), t.Month(), t.Year()) 13 | 14 | time.Sleep(time.Second) 15 | t1 := time.Now() 16 | fmt.Println("Time difference:", t1.Sub(t)) 17 | 18 | formatT := t.Format("01 January 2006") 19 | fmt.Println(formatT) 20 | loc, _ := time.LoadLocation("Europe/Paris") 21 | LondonTime := t.In(loc) 22 | fmt.Println("Paris:", LondonTime) 23 | 24 | } 25 | -------------------------------------------------------------------------------- /eBook/examples/chapter4/findIPv4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io" 7 | "net" 8 | "os" 9 | "path/filepath" 10 | "regexp" 11 | ) 12 | 13 | func findIp(input string) string { 14 | partIp := "(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])" 15 | grammer := partIp+"\\."+partIp+"\\."+partIp+"\\."+partIp 16 | matchMe := regexp.MustCompile(grammer) 17 | return matchMe.FindString(input) 18 | } 19 | 20 | func main() { 21 | arguments := os.Args 22 | if len(arguments) < 2 { 23 | fmt.Printf("usage: %s logfile\n",filepath.Base(arguments[0])) 24 | os.Exit(1) 25 | } 26 | for _, filename := range arguments[1:] { 27 | f,err := os.Open(filename) 28 | if err != nil { 29 | fmt.Printf("error openning file %s\n",err) 30 | os.Exit(-1) 31 | } 32 | defer f.Close() 33 | r := bufio.NewReader(f) 34 | for { 35 | line,err := r.ReadString('\n') 36 | if err == io.EOF { 37 | break 38 | } else if err != nil { 39 | fmt.Printf("error openning file %s\n",err) 40 | break 41 | } 42 | 43 | ip := findIp(line) 44 | trail := net.ParseIP(ip) 45 | if trail.To4() == nil { 46 | continue 47 | } else { 48 | fmt.Println(ip) 49 | } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /eBook/examples/chapter4/pointerStruct.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type myStructure struct { 6 | Name string 7 | Surname string 8 | Height int32 9 | } 10 | 11 | func createStructure(n,s string, h int32) *myStructure { 12 | if h > 300 { 13 | h = 0 14 | } 15 | return &myStructure{n, s, h} 16 | } 17 | 18 | func retStructure(n,s string, h int32) myStructure { 19 | if h > 300 { 20 | h = 0 21 | } 22 | return myStructure{n, s, h} 23 | } 24 | 25 | func main() { 26 | s1 := createStructure("Mihalis","Tsoukalos",123) 27 | s2 := retStructure("Mihalis","Tsoukalos",123) 28 | fmt.Println((*s1).Name) 29 | fmt.Println(s2.Name) 30 | fmt.Println(s1) 31 | fmt.Println(s2) 32 | } 33 | -------------------------------------------------------------------------------- /eBook/examples/chapter4/runes.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | const r1 = '€' 9 | fmt.Println("(int32) r1:", r1) 10 | fmt.Printf("(HEX) r1: %x\n", r1) 11 | fmt.Printf("(as a String) r1: %s\n", r1) 12 | fmt.Printf("(as a character) r1: %c\n", r1) 13 | 14 | fmt.Println("A string is a collection of runes:", []byte("Mihalis")) 15 | aString := []byte("Mihalis") 16 | for x, y := range aString { 17 | fmt.Println(x, y) 18 | fmt.Printf("Char: %c\n", aString[x]) 19 | } 20 | fmt.Printf("%s\n", aString) 21 | } -------------------------------------------------------------------------------- /eBook/examples/chapter4/selectColumn.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io" 7 | "os" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | func main() { 13 | arguments := os.Args 14 | if len(arguments) < 2 { 15 | fmt.Printf("usage: use selectColumn column [file1] [file2] [...]\n") 16 | os.Exit(1) 17 | } 18 | 19 | temp , err := strconv.Atoi(arguments[i]) 20 | if err != nil { 21 | fmt.Printf("column value is not an integer", temp) 22 | return 23 | } 24 | 25 | column := temp 26 | if column < 0 { 27 | fmt.Println("Invalid column value") 28 | os.Exit(1) 29 | } 30 | 31 | for _, fileName := range arguments[2:]{ 32 | fmt.Println("\t\t",fileName) 33 | f, err := os.Open(fileName) 34 | if err != nil { 35 | fmt.Printf("error opening file %s\n",err) 36 | continue 37 | } 38 | f.Close() 39 | 40 | r := bufio.NewReader(f) 41 | for { 42 | line, err := r.ReadString('\n') 43 | if err == io.EOF { 44 | break 45 | } else if err != nil{ 46 | fmt.Printf("error reading file %s\n",err) 47 | } 48 | 49 | data := strings.Fields(line) 50 | if len(data) > column { 51 | fmt.Println(data[column-1]) 52 | } 53 | } 54 | 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /eBook/examples/chapter4/strings.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | const sLiteral= "\x99\x42\x32\x55\x50\x35\x23\x50\x29\x9c" 9 | fmt.Println(sLiteral) 10 | fmt.Printf("x: %x\n", sLiteral) 11 | 12 | fmt.Printf("sLiteral length: %d\n", len(sLiteral)) 13 | 14 | for i := 0; i < len(sLiteral); i++ { 15 | fmt.Printf("%x ", sLiteral[i]) 16 | } 17 | fmt.Println() 18 | 19 | fmt.Printf("q: %q\n", sLiteral) 20 | fmt.Printf("+q: %+q\n", sLiteral) 21 | fmt.Printf(" x: % x\n", sLiteral) 22 | 23 | fmt.Printf("s: As a string: %s\n", sLiteral) 24 | 25 | s2 := "€£³" 26 | for x, y := range s2 { 27 | fmt.Printf("%#U starts at byte position %d\n", y, x) 28 | } 29 | 30 | fmt.Printf("s2 length: %d\n", len(s2)) 31 | 32 | const s3= "ab12AB" 33 | fmt.Println("s3:", s3) 34 | fmt.Printf("x: % x\n", s3) 35 | 36 | fmt.Printf("s3 length: %d\n", len(s3)) 37 | 38 | for i := 0; i < len(s3); i++ { 39 | fmt.Printf("%x ", s3[i]) 40 | } 41 | fmt.Println() 42 | 43 | } -------------------------------------------------------------------------------- /eBook/examples/chapter4/structures.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main(){ 6 | type XYZ struct { 7 | X int 8 | Y int 9 | Z int 10 | } 11 | 12 | var s1 XYZ 13 | fmt.Println(s1.Y, s1.Z) 14 | 15 | p1 := XYZ{23,12, -2} 16 | p2 := XYZ{Z:12,Y:13} 17 | 18 | fmt.Println(p1) 19 | fmt.Println(p2) 20 | 21 | pSlice := [4]XYZ{} 22 | pSlice[2] = p1 23 | pSlice[0] = p2 24 | 25 | fmt.Println(pSlice) 26 | 27 | p2 = XYZ{1,2,3} 28 | fmt.Println(pSlice) 29 | } -------------------------------------------------------------------------------- /eBook/examples/chapter4/switch.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "regexp" 7 | "strconv" 8 | ) 9 | 10 | func main() { 11 | arguments := os.Args 12 | if len(arguments) <2 { 13 | fmt.Println("Usage: switch number") 14 | os.Exit(1) 15 | } 16 | number, err := strconv.Atoi(arguments[1]) 17 | if err != nil { 18 | fmt.Println("The value is not an integer",number) 19 | }else { 20 | switch { 21 | case number<0: 22 | fmt.Println("Less than zero") 23 | case number >0: 24 | fmt.Println("Bigger than zero") 25 | default: 26 | fmt.Println("Zero") 27 | } 28 | } 29 | asString := arguments[1] 30 | switch asString{ 31 | case "5": 32 | fmt.Println("Five") 33 | case "0": 34 | fmt.Println("Zero") 35 | default: 36 | fmt.Println("Do not care") 37 | } 38 | 39 | var negative = regexp.MustCompile(`-`) 40 | var floatingPoint = regexp.MustCompile(`\d?\.\d`) 41 | var mail = regexp.MustCompile(`^[^@]+@[^@.]+\.[^@.]+`) 42 | switch { 43 | case negative.MatchString(asString): 44 | fmt.Println("Negative number") 45 | case floatingPoint.MatchString(asString): 46 | fmt.Println("Floating Point") 47 | case mail.MatchString(asString): 48 | fmt.Println("It is an email") 49 | fallthrough 50 | default: 51 | fmt.Println("Something else") 52 | } 53 | var aType error = nil 54 | switch aType.(type) { 55 | case nil: 56 | fmt.Println("It is a nil interface") 57 | default: 58 | fmt.Println("It it not a nil interface") 59 | 60 | } 61 | 62 | 63 | } -------------------------------------------------------------------------------- /eBook/examples/chapter4/tuples.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func retThree(x int) (int, int, int) { 6 | return 2 * x, x*x,-x 7 | } 8 | 9 | func main() { 10 | fmt.Println(retThree(10)) 11 | n1, n2, n3 := retThree(20) 12 | fmt.Println(n1,n2,n3) 13 | 14 | n1, n2 = n2, n1 15 | fmt.Println(n1, n2, n3) 16 | 17 | x1, x2, x3 := n1*2,n1*n1, -n1 18 | 19 | fmt.Println(x1,x2,x3) 20 | } -------------------------------------------------------------------------------- /eBook/examples/chapter4/unicode.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unicode" 6 | ) 7 | 8 | func main() { 9 | const sL= "\x99\x00ab\x50\x00\x23\x50\x29\x9c" 10 | 11 | for i := 0; i < len(sL); i++ { 12 | if unicode.IsPrint(rune(sL[i])) { 13 | fmt.Printf("%c\n", sL[i]) 14 | } else { 15 | fmt.Println("Not printable!") 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /eBook/examples/chapter5/binTree.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | type Tree struct { 10 | Left *Tree 11 | Value int 12 | Right *Tree 13 | } 14 | 15 | func traverse(t *Tree) { 16 | if t == nil { 17 | return 18 | } 19 | traverse(t.Left) 20 | fmt.Println(t.Value, " ") 21 | traverse(t.Right) 22 | } 23 | 24 | func create(n int) *Tree { 25 | var t *Tree 26 | rand.Seed(time.Now().Unix()) 27 | for i := 0; i < 2*n; i++ { 28 | temp := rand.Intn(n * 2) 29 | t = insert(t, temp) 30 | } 31 | return t 32 | } 33 | 34 | func insert(t *Tree, v int) *Tree { 35 | if t == nil { 36 | return &Tree{nil, v, nil} 37 | } 38 | if v == t.Value { 39 | return t 40 | } 41 | if v < t.Value { 42 | t.Left = insert(t.Left, v) 43 | return t 44 | } 45 | t.Right = insert(t.Right, v) 46 | return t 47 | } 48 | 49 | func main() { 50 | tree := create(10) 51 | fmt.Println("The value of the root of the tree is", tree.Value) 52 | traverse(tree) 53 | fmt.Println() 54 | tree = insert(tree, -10) 55 | tree = insert(tree, -2) 56 | traverse(tree) 57 | fmt.Println() 58 | fmt.Println("The value of the root of the tree is", tree.Value) 59 | } 60 | -------------------------------------------------------------------------------- /eBook/examples/chapter5/conHeap.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "container/heap" 5 | "fmt" 6 | ) 7 | 8 | type heapFloat32 []float32 9 | 10 | func (n *heapFloat32) Pop() interface{} { 11 | old := *n 12 | x := old[len(old)-1] 13 | new := old[0 : len(old)-1] 14 | *n = new 15 | return x 16 | } 17 | 18 | func (n *heapFloat32) Push(x interface{}) { 19 | *n = append(*n, x.(float32)) 20 | } 21 | 22 | func (n heapFloat32) Len() int { 23 | return len(n) 24 | } 25 | 26 | func (n heapFloat32) Less(a, b int) bool { 27 | return n[a] < n[b] 28 | } 29 | 30 | func (n heapFloat32) Swap(a, b int) { 31 | n[a], n[b] = n[b], n[a] 32 | } 33 | 34 | func main() { 35 | myHeap := &heapFloat32{1.2, 2.1, 3.1, -100.1} 36 | heap.Init(myHeap) 37 | size := len(*myHeap) 38 | fmt.Printf("Heap size: %d\n", size) 39 | fmt.Printf("%v\n", myHeap) 40 | myHeap.Push(float32(-100.2)) 41 | myHeap.Push(float32(0.2)) 42 | fmt.Printf("Heap size: %d\n", len(*myHeap)) 43 | fmt.Printf("%v\n", myHeap) 44 | heap.Init(myHeap) 45 | fmt.Printf("%v\n", myHeap) 46 | } 47 | -------------------------------------------------------------------------------- /eBook/examples/chapter5/conList.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "container/list" 5 | "fmt" 6 | "strconv" 7 | ) 8 | 9 | func printList(l *list.List) { 10 | for t := l.Back(); t != nil; t = t.Prev() { 11 | fmt.Print(t.Value, " ") 12 | } 13 | fmt.Println() 14 | 15 | for t := l.Front(); t != nil; t = t.Next() { 16 | fmt.Print(t.Value, " ") 17 | } 18 | 19 | fmt.Println() 20 | } 21 | 22 | func main() { 23 | 24 | values := list.New() 25 | 26 | e1 := values.PushBack("One") 27 | e2 := values.PushBack("Two") 28 | values.PushFront("Three") 29 | values.InsertBefore("Four", e1) 30 | values.InsertAfter("Five", e2) 31 | values.Remove(e2) 32 | values.Remove(e2) 33 | values.InsertAfter("FiveFive", e2) 34 | values.PushBackList(values) 35 | 36 | printList(values) 37 | 38 | values.Init() 39 | fmt.Printf("After Init(): %v\n", values) 40 | 41 | for i := 0; i < 20; i++ { 42 | values.PushFront(strconv.Itoa(i)) 43 | } 44 | 45 | printList(values) 46 | } 47 | -------------------------------------------------------------------------------- /eBook/examples/chapter5/conRing.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "container/ring" 5 | "fmt" 6 | ) 7 | 8 | var size int = 10 9 | 10 | func main() { 11 | myRing := ring.New(size + 1) 12 | fmt.Println("Empty ring:", *myRing) 13 | 14 | for i := 0; i < myRing.Len()-1; i++ { 15 | myRing.Value = i 16 | myRing = myRing.Next() 17 | } 18 | 19 | myRing.Value = 2 20 | 21 | sum := 0 22 | myRing.Do(func(x interface{}) { 23 | t := x.(int) 24 | sum = sum + t 25 | }) 26 | fmt.Println("Sum:", sum) 27 | 28 | for i := 0; i < myRing.Len()+2; i++ { 29 | myRing = myRing.Next() 30 | fmt.Print(myRing.Value, " ") 31 | } 32 | fmt.Println() 33 | } 34 | -------------------------------------------------------------------------------- /eBook/examples/chapter5/generatePassword.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "os" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | func random(min, max int) int { 12 | return rand.Intn(max-min) + min 13 | } 14 | 15 | func main() { 16 | MIN := 0 17 | MAX := 94 18 | SEED := time.Now().Unix() 19 | var LENGTH int64 = 8 20 | 21 | arguments := os.Args 22 | switch len(arguments) { 23 | case 2: 24 | LENGTH, _ = strconv.ParseInt(os.Args[1], 10, 64) 25 | default: 26 | fmt.Println("Using default values!") 27 | } 28 | 29 | rand.Seed(SEED) 30 | 31 | startChar := "!" 32 | var i int64 = 1 33 | for { 34 | myRand := random(MIN, MAX) 35 | newChar := string(startChar[0] + byte(myRand)) 36 | fmt.Print(newChar) 37 | if i == LENGTH { 38 | break 39 | } 40 | i++ 41 | } 42 | fmt.Println() 43 | } 44 | -------------------------------------------------------------------------------- /eBook/examples/chapter5/hashTable.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | const SIZE = 15 6 | 7 | type Node struct { 8 | Value int 9 | Next *Node 10 | } 11 | 12 | type HashTable struct { 13 | Table map[int]*Node 14 | Size int 15 | } 16 | 17 | func hashFunction(i, size int) int { 18 | return (i % size) 19 | } 20 | 21 | func insert(hash *HashTable, value int) int { 22 | index := hashFunction(value, hash.Size) 23 | element := Node{Value: value, Next: hash.Table[index]} 24 | hash.Table[index] = &element 25 | return index 26 | } 27 | 28 | func traverse(hash *HashTable) { 29 | for k := range hash.Table { 30 | if hash.Table[k] != nil { 31 | t := hash.Table[k] 32 | for t != nil { 33 | fmt.Printf("%d -> ", t.Value) 34 | t = t.Next 35 | } 36 | } 37 | fmt.Println() 38 | } 39 | } 40 | 41 | func main() { 42 | table := make(map[int]*Node, SIZE) 43 | hash := &HashTable{Table: table, Size: SIZE} 44 | fmt.Println("Numbder of spaces:", hash.Size) 45 | for i := 0; i < 120; i++ { 46 | insert(hash, i) 47 | } 48 | traverse(hash) 49 | } 50 | -------------------------------------------------------------------------------- /eBook/examples/chapter5/hashTableLookup.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | const SIZE = 15 8 | 9 | type Node struct { 10 | Value int 11 | Next *Node 12 | } 13 | 14 | type HashTable struct { 15 | Table map[int]*Node 16 | Size int 17 | } 18 | 19 | func hashFunction(i, size int) int { 20 | return (i % size) 21 | } 22 | 23 | func insert(hash *HashTable, value int) int { 24 | index := hashFunction(value, hash.Size) 25 | element := Node{Value: value, Next: hash.Table[index]} 26 | hash.Table[index] = &element 27 | return index 28 | } 29 | 30 | func traverse(hash *HashTable) { 31 | for k := range hash.Table { 32 | if hash.Table[k] != nil { 33 | t := hash.Table[k] 34 | for t != nil { 35 | fmt.Printf("%d -> ", t.Value) 36 | t = t.Next 37 | } 38 | fmt.Println() 39 | } 40 | } 41 | } 42 | 43 | func lookup(hash *HashTable, value int) bool { 44 | index := hashFunction(value, hash.Size) 45 | if hash.Table[index] != nil { 46 | t := hash.Table[index] 47 | for t != nil { 48 | if t.Value == value { 49 | return true 50 | } 51 | t = t.Next 52 | } 53 | } 54 | return false 55 | } 56 | 57 | func main() { 58 | table := make(map[int]*Node, SIZE) 59 | hash := &HashTable{Table: table, Size: SIZE} 60 | for i := 0; i < 120; i++ { 61 | insert(hash, i) 62 | } 63 | 64 | for i := 10; i < 125; i++ { 65 | if !lookup(hash, i) { 66 | fmt.Println(i, "is not in the hash table!") 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /eBook/examples/chapter5/randomNumbers.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "os" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | func random(min, max int) int { 12 | return rand.Intn(max-min) + min 13 | } 14 | 15 | func main() { 16 | MIN := 0 17 | MAX := 100 18 | TOTAL := 100 19 | SEED := time.Now().Unix() 20 | 21 | arguments := os.Args 22 | switch len(arguments) { 23 | case 2: 24 | fmt.Println("Usage: ./randomNumbers MIN MAX TOTAL SEED") 25 | MIN, _ = strconv.Atoi(arguments[1]) 26 | MAX = MIN + 100 27 | case 3: 28 | fmt.Println("Usage: ./randomNumbers MIN MAX TOTAL SEED") 29 | MIN, _ = strconv.Atoi(arguments[1]) 30 | MAX, _ = strconv.Atoi(arguments[2]) 31 | case 4: 32 | fmt.Println("Usage: ./randomNumbers MIN MAX TOTAL SEED") 33 | MIN, _ = strconv.Atoi(arguments[1]) 34 | MAX, _ = strconv.Atoi(arguments[2]) 35 | TOTAL, _ = strconv.Atoi(arguments[3]) 36 | case 5: 37 | MIN, _ = strconv.Atoi(arguments[1]) 38 | MAX, _ = strconv.Atoi(arguments[2]) 39 | TOTAL, _ = strconv.Atoi(arguments[3]) 40 | SEED, _ = strconv.ParseInt(arguments[4], 10, 64) 41 | default: 42 | fmt.Println("Using default values!") 43 | } 44 | 45 | rand.Seed(SEED) 46 | for i := 0; i < TOTAL; i++ { 47 | myrand := random(MIN, MAX) 48 | fmt.Print(myrand) 49 | fmt.Print(" ") 50 | } 51 | fmt.Println() 52 | } -------------------------------------------------------------------------------- /eBook/examples/chapter5/stack.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type Node struct { 8 | Value int 9 | Next *Node 10 | } 11 | 12 | var size = 0 13 | var stack = new(Node) 14 | 15 | func Push(v int) bool { 16 | if stack == nil { 17 | stack = &Node{v, nil} 18 | size = 1 19 | return true 20 | } 21 | 22 | temp := &Node{v, nil} 23 | temp.Next = stack 24 | stack = temp 25 | size++ 26 | return true 27 | } 28 | 29 | func Pop(t *Node) (int, bool) { 30 | if size == 0 { 31 | return 0, false 32 | } 33 | 34 | if size == 1 { 35 | size = 0 36 | stack = nil 37 | return t.Value, true 38 | } 39 | 40 | stack = stack.Next 41 | size-- 42 | return t.Value, true 43 | } 44 | 45 | func traverse(t *Node) { 46 | if size == 0 { 47 | fmt.Println("Empty Stack!") 48 | return 49 | } 50 | 51 | for t != nil { 52 | fmt.Printf("%d -> ", t.Value) 53 | t = t.Next 54 | } 55 | fmt.Println() 56 | } 57 | 58 | func main() { 59 | 60 | stack = nil 61 | v, b := Pop(stack) 62 | if b { 63 | fmt.Print(v, " ") 64 | } else { 65 | fmt.Println("Pop() failed!") 66 | } 67 | 68 | Push(100) 69 | traverse(stack) 70 | Push(200) 71 | traverse(stack) 72 | 73 | for i := 0; i < 10; i++ { 74 | Push(i) 75 | } 76 | 77 | for i := 0; i < 15; i++ { 78 | v, b := Pop(stack) 79 | if b { 80 | fmt.Print(v, " ") 81 | } else { 82 | break 83 | } 84 | } 85 | fmt.Println() 86 | traverse(stack) 87 | } -------------------------------------------------------------------------------- /eBook/examples/chapter6/aPackage.go: -------------------------------------------------------------------------------- 1 | package aPackage 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func A() { 8 | fmt.Println("This is function A!") 9 | } 10 | ``` 11 | 12 | `aPackage.go` 的第二部分代码如下: 13 | 14 | ```go 15 | func B() { 16 | fmt.Println("privateConstant:", privateConstant) 17 | } 18 | 19 | const MyConstant = 123 20 | const privateConstant = 21 -------------------------------------------------------------------------------- /eBook/examples/chapter6/funFun.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func function1(i int) int { 6 | return i + i 7 | } 8 | 9 | func function2(i int) int { 10 | return i * i 11 | } 12 | 13 | func funFun(f func(int) int, v int) int { 14 | return f(v) 15 | } 16 | 17 | func main() { 18 | fmt.Println("function1:", funFun(function1, 123)) 19 | fmt.Println("function2:", funFun(function2, 123)) 20 | fmt.Println("Inline:", funFun(func(i int) int {return i * i * i}, 123)) 21 | } -------------------------------------------------------------------------------- /eBook/examples/chapter6/functions.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | ) 8 | 9 | func doubleSquare(x int) (int, int) { 10 | return x * 2, x * x 11 | } 12 | 13 | func main() { 14 | arguments := os.Args 15 | if len(arguments) != 2 { 16 | fmt.Println("The program needs 1 argument!") 17 | return 18 | } 19 | y, err := strconv.Atoi(arguments[1]) 20 | if err != nil { 21 | fmt.Println(err) 22 | return 23 | } 24 | 25 | square := func(s int) int { 26 | return s * s 27 | } 28 | fmt.Println("The squre of", y, "is", square(y)) 29 | 30 | double := func(s int) int { 31 | return s + s 32 | } 33 | fmt.Println("The double of", y, "is", double(y)) 34 | 35 | fmt.Println(doubleSquare(y)) 36 | d, s := doubleSquare(y) 37 | fmt.Println(d, s) 38 | } -------------------------------------------------------------------------------- /eBook/examples/chapter6/ptrFun.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func getPtr(v *float64) float64 { 8 | return *v * *v 9 | } 10 | 11 | func main() { 12 | x := 12.2 13 | fmt.Println(getPrt(&x)) 14 | x = 12 15 | fmt.Println(getPtr(&x)) 16 | } -------------------------------------------------------------------------------- /eBook/examples/chapter6/returnFunction.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func funReturnFun() func() int { 8 | i := 0 9 | return func() int { 10 | i++ 11 | return i * i 12 | } 13 | } 14 | 15 | func main(){ 16 | i := funReturnFun() 17 | j := funReturnFun() 18 | 19 | fmt.Println("1:", i()) 20 | fmt.Println("2:", i()) 21 | fmt.Println("j1:", j()) 22 | fmt.Println("j2:", j()) 23 | fmt.Println("3:", i()) 24 | } -------------------------------------------------------------------------------- /eBook/examples/chapter6/returnNames.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | ) 8 | 9 | func namedMinMax(x, y int) (min, max int) { 10 | if x > y { 11 | min = y 12 | max = x 13 | } else { 14 | min = x 15 | max = y 16 | } 17 | return 18 | } 19 | 20 | func minMax(x, y int) (min, max int) { 21 | if x > y { 22 | min = y 23 | max = x 24 | } else { 25 | min = x 26 | max = y 27 | } 28 | return min, max 29 | } 30 | 31 | func main() { 32 | arguments := os.Args 33 | if len(arguments) < 3 { 34 | fmt.Println("The program needs at least 2 arguments!") 35 | return 36 | } 37 | a1, _ := strconv.Atoi(arguments[1]) 38 | a2, _ := strconv.Atoi(arguments[2]) 39 | 40 | fmt.Println(minMax(a1, a2)) 41 | min, max := minMax(a1, a2) 42 | fmt.Println(min, max) 43 | 44 | fmt.Println(namedMinMax(a1, a2)) 45 | min, max = namedMinMax(a1, a2) 46 | fmt.Println(min, max) 47 | } -------------------------------------------------------------------------------- /eBook/examples/chapter6/returnPtr.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func returnPtr(x int) *int { 8 | y := x * x 9 | return &y 10 | } 11 | 12 | func main() { 13 | sq := returnPtr(10) 14 | fmt.Println("sq:", *sq) 15 | fmt.Println("sq:", sq) 16 | } -------------------------------------------------------------------------------- /eBook/examples/chapter6/useAPackage.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "aPackage" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | fmt.Println("Using aPackage!") 10 | aPackage.A() 11 | aPackage.B() 12 | fmt.Println(aPackage.MyConstant) 13 | } -------------------------------------------------------------------------------- /eBook/examples/chapter7/advRefl.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "reflect" 7 | ) 8 | 9 | type t1 int 10 | type t2 int 11 | 12 | type a struct { 13 | X int 14 | Y float64 15 | Text string 16 | } 17 | 18 | func (a1 a) compareStruct(a2 a) bool { 19 | r1 := reflect.ValueOf(&a1).Elem() 20 | r2 := reflect.ValueOf(&a2).Elem() 21 | for i := 0; i < r1.NumField(); i++ { 22 | if r1.Field(i).Interface() != r2.Field(i).Interface() { 23 | return false 24 | } 25 | } 26 | return true 27 | } 28 | 29 | func printMethods(i interface{}) { 30 | r := reflect.ValueOf(i) 31 | t := r.Type() 32 | fmt.Printf("Type to examine: %s\n", t) 33 | for j := 0; j < r.NumMethod(); j++ { 34 | m := r.Method(j).Type() 35 | fmt.Println(t.Method(j).Name, "-->", m) 36 | } 37 | } 38 | 39 | func main() { 40 | x1 := t1(100) 41 | x2 := t2(100) 42 | fmt.Printf("The type of x1 is %s\n", reflect.TypeOf(x1)) 43 | fmt.Printf("The type of x2 is %s\n", reflect.TypeOf(x2)) 44 | var p struct{} 45 | r := reflect.New(reflect.ValueOf(&p).Type()).Elem() 46 | fmt.Printf("The type of r is %s\n", reflect.TypeOf(r)) 47 | a1 := a{1, 2.1, "A1"} 48 | a2 := a{1, -2, "A2"} 49 | if a1.compareStruct(a1) { 50 | fmt.Println("Equal!") 51 | } 52 | if !a1.compareStruct(a2) { 53 | fmt.Println("Not Equal!") 54 | } 55 | var f *os.File 56 | printMethods(f) 57 | } 58 | -------------------------------------------------------------------------------- /eBook/examples/chapter7/assertion.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | var myInt interface{} = 123 9 | k, ok := myInt.(int) 10 | if ok { 11 | fmt.Println("Success:", k) 12 | } 13 | v, ok := myInt.(float64) 14 | if ok { 15 | fmt.Println(v) 16 | } else { 17 | fmt.Println("Failed without panicking!") 18 | } 19 | i := myInt.(int) 20 | fmt.Println("No cheking:", i) 21 | j := myInt.(bool) 22 | fmt.Println(j) 23 | } 24 | -------------------------------------------------------------------------------- /eBook/examples/chapter7/goCoIn.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type first struct{} 8 | 9 | func (a first) F() { 10 | a.shared() 11 | } 12 | 13 | func (a first) shared() { 14 | fmt.Println("This is shared() from first!") 15 | } 16 | 17 | type second struct { 18 | first 19 | } 20 | 21 | func (a second) shared() { 22 | fmt.Println("This is shared() from second!") 23 | } 24 | 25 | func main() { 26 | first{}.F() 27 | second{}.shared() 28 | i := second{} 29 | j := i.first 30 | j.F() 31 | } 32 | -------------------------------------------------------------------------------- /eBook/examples/chapter7/methods.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type twoInts struct { 8 | X int64 9 | Y int64 10 | } 11 | 12 | func regularFunction(a, b twoInts) twoInts { 13 | temp := twoInts{X: a.X + b.X, Y: a.Y + b.Y} 14 | return temp 15 | } 16 | 17 | func (a twoInts) method(b twoInts) twoInts { 18 | temp := twoInts{X: a.X + b.X, Y: a.Y + b.Y} 19 | return temp 20 | } 21 | 22 | func main() { 23 | i := twoInts{X: 1, Y: 2} 24 | j := twoInts{X: -5, Y: -2} 25 | fmt.Println(regularFunction(i, j)) 26 | fmt.Println(i.method(j)) 27 | } 28 | -------------------------------------------------------------------------------- /eBook/examples/chapter7/myInterface.go: -------------------------------------------------------------------------------- 1 | package myInterface 2 | 3 | type Shape interface { 4 | Area() float64 5 | Perimeter() float64 6 | } -------------------------------------------------------------------------------- /eBook/examples/chapter7/ooo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type a struct { 8 | XX int 9 | YY int 10 | } 11 | type b struct { 12 | AA string 13 | XX int 14 | } 15 | 16 | type c struct { 17 | A a 18 | B b 19 | } 20 | 21 | func (A a) A() { 22 | fmt.Println("Function A() for A") 23 | } 24 | 25 | func (B b) A() { 26 | fmt.Println("Function A() for B") 27 | } 28 | 29 | func main() { 30 | var i c 31 | i.A.A() 32 | i.B.A() 33 | } 34 | -------------------------------------------------------------------------------- /eBook/examples/chapter7/reflection.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "reflect" 7 | ) 8 | 9 | type a struct { 10 | X int 11 | Y float64 12 | Z string 13 | } 14 | 15 | type b struct { 16 | F int 17 | G int 18 | H string 19 | I float64 20 | } 21 | 22 | func main() { 23 | x := 100 24 | xRefl := reflect.ValueOf(&x).Elem() 25 | xType := xRefl.Type() 26 | fmt.Printf("The type of x is %s.\n", xType) 27 | 28 | A := a{100, 200.12, "Struct a"} 29 | B := b{1, 2, "Struct b", -1.2} 30 | var r reflect.Value 31 | 32 | arguments := os.Args 33 | if len(arguments) == 1 { 34 | r = reflect.ValueOf(&A).Elem() 35 | } else { 36 | r = reflect.ValueOf(&B).Elem() 37 | } 38 | 39 | iType := r.Type() 40 | fmt.Printf("i Type: %s\n", iType) 41 | fmt.Printf("The %d fields of %s are:\n", r.NumField(), iType) 42 | 43 | for i := 0; i < r.NumField(); i++ { 44 | fmt.Printf("Field name: %s ", iType.Field(i).Name) 45 | fmt.Printf("with type: %s ", r.Field(i).Type()) 46 | fmt.Printf("and value %v\n", r.Field(i).Interface()) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /eBook/examples/chapter7/switch.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type square struct { 8 | X float64 9 | } 10 | 11 | type circle struct { 12 | R float64 13 | } 14 | 15 | type rectangle struct { 16 | X float64 17 | Y float64 18 | } 19 | 20 | func tellInterface(x interface{}) { 21 | switch v := x.(type) { 22 | case square: 23 | fmt.Println("This is a square!") 24 | case circle: 25 | fmt.Printf("%v is a circle!\n", v) 26 | case rectangle: 27 | fmt.Println("This is a rectangle!") 28 | default: 29 | fmt.Printf("Unknown type %T!\n", v) 30 | } 31 | } 32 | 33 | func main() { 34 | x := circle{R: 10} 35 | tellInterface(x) 36 | y := rectangle{X: 4, Y: 1} 37 | tellInterface(y) 38 | z := square{X: 4} 39 | tellInterface(z) 40 | tellInterface(10) 41 | } 42 | -------------------------------------------------------------------------------- /eBook/examples/chapter7/useInterface.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "myInterface" 7 | ) 8 | 9 | type square struct { 10 | X float64 11 | } 12 | 13 | type circle struct { 14 | R float64 15 | } 16 | 17 | func (s square) Area() float64 { 18 | return s.X * s.X 19 | } 20 | 21 | func (s square) Perimeter() float64 { 22 | return 4 * s.X 23 | } 24 | 25 | func (s circle) Area() float64 { 26 | return s.R * s.R * math.Pi 27 | } 28 | 29 | func (s circle) Perimeter() float64 { 30 | return 2 * s.R * math.Pi 31 | } 32 | 33 | func Calculate(x myInterface.Shape) { 34 | _, ok := x.(circle) 35 | if ok { 36 | fmt.Println("Is a circle!") 37 | } 38 | v, ok := x.(square) 39 | if ok { 40 | fmt.Println("Is a square:", v) 41 | } 42 | fmt.Println(x.Area()) 43 | fmt.Println(x.Perimeter()) 44 | } 45 | 46 | func main() { 47 | x := square{X: 10} 48 | fmt.Println("Perimeter:", x.Perimeter()) 49 | Calculate(x) 50 | y := circle{R: 5} 51 | Calculate(y) 52 | } 53 | -------------------------------------------------------------------------------- /eBook/examples/chapter8/funWithFlag.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import( 4 | "flag" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | type NamesFlag struct { 10 | Names []string 11 | } 12 | 13 | func (s *NamesFlag) GetNames() []string{ 14 | return s.Names 15 | } 16 | func (s *NamesFlag) String() string { 17 | return fmt.Sprint(s.Names) 18 | } 19 | func (s *NamesFlag) Set(v string) error { 20 | if len(s.Names) > 0 { 21 | return fmt.Errorf("Cannot use names flag more than once!") 22 | } 23 | 24 | names := strings.Split(v, ",") 25 | for _, item := range names { 26 | s.Names = append(s.Names, item) 27 | } 28 | return nil 29 | } 30 | func main() { 31 | var manyNames NamesFlag 32 | minusK := flag.Int("k:", 0, "An int") 33 | minusO := flag.String("o", "Mihalis", "The name") 34 | flag.Var(&manyNames, "names", "Comma-separated list") 35 | 36 | flag.Parse() 37 | fmt.Println("-k:", *minusK) 38 | fmt.Println("-o:", *minusO) 39 | for i, item := range manyNames.GetNames() { 40 | fmt.Println(i, item) 41 | } 42 | fmt.Println("Remaing command-line arugments:") 43 | for index, val := range flag.Args() { 44 | fmt.Println(index, ":", val) 45 | } 46 | } -------------------------------------------------------------------------------- /eBook/examples/chapter8/simpleFlag.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | ) 7 | 8 | func main(){ 9 | minusk := flag.Bool("k", true, "k") 10 | minusO := flag.Int("O", 1, "O") 11 | flag.Parse() 12 | 13 | valueK := *minusk 14 | valueO := *minusO 15 | valueO++ 16 | 17 | fmt.Println("-k:", valueK) 18 | fmt.Println("-O:", valueO) 19 | } -------------------------------------------------------------------------------- /eBook/examples/chapter9/create.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | n := flag.Int("n", 10, "Number of goroutines") 11 | flag.Parse() 12 | 13 | count := *n 14 | fmt.Printf("Going to create %d goroutines.\n", count) 15 | 16 | for i := 0; i < count; i++ { 17 | go func(x int) { 18 | fmt.Printf("%d ", x) 19 | }(i) 20 | } 21 | time.Sleep(time.Second) 22 | fmt.Println("\nExiting...") 23 | } 24 | -------------------------------------------------------------------------------- /eBook/examples/chapter9/pipeline.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "os" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | var CLOSEA = false 12 | var DATA = make(map[int]bool) 13 | 14 | func random(min, max int) int { 15 | return rand.Intn(max-min) + min 16 | } 17 | 18 | func first(min, max int, out chan<- int) { 19 | for { 20 | if CLOSEA { 21 | close(out) 22 | return 23 | } 24 | out <- random(min, max) 25 | } 26 | } 27 | 28 | func second(out chan<- int, in <-chan int) { 29 | for x := range in { 30 | fmt.Print(x, " ") 31 | _, ok := DATA[x] 32 | if ok { 33 | CLOSEA = true 34 | } else { 35 | DATA[x] = true 36 | out <- x 37 | } 38 | } 39 | fmt.Println() 40 | close(out) 41 | } 42 | 43 | func third(in <-chan int) { 44 | var sum int 45 | sum = 0 46 | for x2 := range in { 47 | sum = sum + x2 48 | } 49 | fmt.Println("The sum of the random numbers is %d\n", sum) 50 | } 51 | 52 | func main() { 53 | if len(os.Args) != 3 { 54 | fmt.Println("Need two integer paramters!") 55 | os.Exit(1) 56 | } 57 | n1, _ := strconv.Atoi(os.Args[1]) 58 | n2, _ := strconv.Atoi(os.Args[2]) 59 | 60 | if n1 > n2 { 61 | fmt.Printf("%d should be smaller than %d\n", n1, n2) 62 | return 63 | } 64 | rand.Seed(time.Now().UnixNano()) 65 | A := make(chan int) 66 | B := make(chan int) 67 | 68 | go first(n1, n2, A) 69 | go second(B, A) 70 | third(B) 71 | } 72 | -------------------------------------------------------------------------------- /eBook/examples/chapter9/readCh.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func writeToChannel(c chan int, x int) { 9 | fmt.Println("l", x) 10 | c <- x 11 | close(c) 12 | fmt.Println("2", x) 13 | } 14 | 15 | func main() { 16 | c := make(chan int) 17 | go writeToChannel(c, 10) 18 | time.Sleep(1 * time.Second) 19 | fmt.Println("Read:", <-c) 20 | time.Sleep(1 * time.Second) 21 | _, ok := <-c 22 | if ok { 23 | fmt.Println("Channel is open!") 24 | } else { 25 | fmt.Println("Channel is closed!") 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /eBook/examples/chapter9/simple.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func function() { 9 | for i := 0; i < 10; i++ { 10 | fmt.Print(i) 11 | } 12 | fmt.Println() 13 | } 14 | 15 | func main() { 16 | go function() 17 | go func() { 18 | for i := 10; i < 20; i++ { 19 | fmt.Print(i, " ") 20 | } 21 | }() 22 | 23 | time.Sleep(1 * time.Second) 24 | } 25 | -------------------------------------------------------------------------------- /eBook/examples/chapter9/syncGo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "sync" 7 | ) 8 | 9 | func main() { 10 | n := flag.Int("n", 20, "Number of goroutines") 11 | flag.Parse() 12 | count := *n 13 | fmt.Printf("Going to create %d goroutines.\n", count) 14 | 15 | var waitGroup sync.WaitGroup 16 | fmt.Printf("%#v\n", waitGroup) 17 | for i := 0; i < count; i++ { 18 | waitGroup.Add(1) 19 | go func(x int) { 20 | defer waitGroup.Done() 21 | fmt.Printf("%d ", x) 22 | }(i) 23 | } 24 | 25 | fmt.Printf("%#v\n", waitGroup) 26 | waitGroup.Wait() 27 | fmt.Println("\nExiting...") 28 | } 29 | -------------------------------------------------------------------------------- /eBook/examples/chapter9/writeCh.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func writeToChannel(c chan int, x int) { 9 | fmt.Println(x) 10 | c <- x 11 | close(c) 12 | fmt.Println(x) 13 | } 14 | 15 | func main() { 16 | c := make(chan int) 17 | go writeToChannel(c, 10) 18 | time.Sleep(1 * time.Second) 19 | } 20 | -------------------------------------------------------------------------------- /images/chapter10/10.1-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter10/10.1-1.jpg -------------------------------------------------------------------------------- /images/chapter10/10.4.5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter10/10.4.5.jpg -------------------------------------------------------------------------------- /images/chapter10/10.5.1-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter10/10.5.1-1.jpg -------------------------------------------------------------------------------- /images/chapter10/10.5.1-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter10/10.5.1-2.jpg -------------------------------------------------------------------------------- /images/chapter10/10.5.1-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter10/10.5.1-3.jpg -------------------------------------------------------------------------------- /images/chapter10/10.6-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter10/10.6-1.jpg -------------------------------------------------------------------------------- /images/chapter10/10.6-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter10/10.6-2.jpg -------------------------------------------------------------------------------- /images/chapter10/10.7.1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter10/10.7.1.jpg -------------------------------------------------------------------------------- /images/chapter11/11.13-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.13-1.jpg -------------------------------------------------------------------------------- /images/chapter11/11.13-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.13-2.jpg -------------------------------------------------------------------------------- /images/chapter11/11.13-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.13-3.jpg -------------------------------------------------------------------------------- /images/chapter11/11.13-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.13-4.jpg -------------------------------------------------------------------------------- /images/chapter11/11.2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.2.jpg -------------------------------------------------------------------------------- /images/chapter11/11.5.2-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.5.2-1.jpg -------------------------------------------------------------------------------- /images/chapter11/11.5.2-2.1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.5.2-2.1.jpg -------------------------------------------------------------------------------- /images/chapter11/11.5.2-2.2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.5.2-2.2.jpg -------------------------------------------------------------------------------- /images/chapter11/11.5.2-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.5.2-3.jpg -------------------------------------------------------------------------------- /images/chapter11/11.5.2-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.5.2-4.jpg -------------------------------------------------------------------------------- /images/chapter11/11.5.2-5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.5.2-5.jpg -------------------------------------------------------------------------------- /images/chapter11/11.5.2-6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.5.2-6.jpg -------------------------------------------------------------------------------- /images/chapter11/11.5.3-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.5.3-1.jpg -------------------------------------------------------------------------------- /images/chapter11/11.5.3-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.5.3-2.jpg -------------------------------------------------------------------------------- /images/chapter11/11.5.4.1-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.5.4.1-1.jpg -------------------------------------------------------------------------------- /images/chapter11/11.5.4.1-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.5.4.1-2.jpg -------------------------------------------------------------------------------- /images/chapter11/11.5.4.2-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.5.4.2-1.jpg -------------------------------------------------------------------------------- /images/chapter11/11.5.4.2-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.5.4.2-2.jpg -------------------------------------------------------------------------------- /images/chapter11/11.6-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.6-1.jpg -------------------------------------------------------------------------------- /images/chapter11/11.6-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.6-2.jpg -------------------------------------------------------------------------------- /images/chapter11/11.6-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.6-3.jpg -------------------------------------------------------------------------------- /images/chapter11/11.7.1-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.7.1-1.jpg -------------------------------------------------------------------------------- /images/chapter11/11.7.1-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.7.1-2.jpg -------------------------------------------------------------------------------- /images/chapter11/11.7.1-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.7.1-3.jpg -------------------------------------------------------------------------------- /images/chapter11/11.8.1-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.8.1-1.jpg -------------------------------------------------------------------------------- /images/chapter11/11.8.1-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.8.1-2.jpg -------------------------------------------------------------------------------- /images/chapter11/11.9-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.9-1.jpg -------------------------------------------------------------------------------- /images/chapter11/11.9-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter11/11.9-2.jpg -------------------------------------------------------------------------------- /images/chapter12/12.7.1-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter12/12.7.1-1.jpg -------------------------------------------------------------------------------- /images/chapter12/12.7.1-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter12/12.7.1-2.jpg -------------------------------------------------------------------------------- /images/chapter12/12.7.2-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter12/12.7.2-1.jpg -------------------------------------------------------------------------------- /images/chapter12/12.7.2-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter12/12.7.2-2.jpg -------------------------------------------------------------------------------- /images/chapter12/12.7.2-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter12/12.7.2-3.jpg -------------------------------------------------------------------------------- /images/chapter12/12.7.2-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter12/12.7.2-4.jpg -------------------------------------------------------------------------------- /images/chapter12/12.9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter12/12.9.jpg -------------------------------------------------------------------------------- /images/chapter2/02.3-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter2/02.3-1.jpg -------------------------------------------------------------------------------- /images/chapter5/05.3-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter5/05.3-1.jpg -------------------------------------------------------------------------------- /images/chapter5/05.4-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter5/05.4-1.jpg -------------------------------------------------------------------------------- /images/chapter5/05.5-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter5/05.5-1.jpg -------------------------------------------------------------------------------- /images/chapter5/05.5-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter5/05.5-2.jpg -------------------------------------------------------------------------------- /images/chapter5/05.6-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter5/05.6-1.jpg -------------------------------------------------------------------------------- /images/chapter5/05.6-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter5/05.6-2.jpg -------------------------------------------------------------------------------- /images/chapter8/08.2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter8/08.2.jpg -------------------------------------------------------------------------------- /images/chapter8/08.8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/chapter8/08.8.png -------------------------------------------------------------------------------- /images/cover.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hantmac/Mastering_Go_ZH_CN/d2fda325b3ae057994c3c6bb484f55ba2fb5dbaf/images/cover.jpeg --------------------------------------------------------------------------------